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.TbMsgMetaData;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@Slf4j
|
||||
@ -46,10 +47,9 @@ public abstract class TbAbstractNodeWithFetchTo<C extends TbAbstractFetchToNodeC
|
||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||
config = loadNodeConfiguration(configuration);
|
||||
if (config.getFetchTo() == null) {
|
||||
throw new TbNodeException("FetchTo cannot be null!");
|
||||
} else {
|
||||
fetchTo = config.getFetchTo();
|
||||
throw new TbNodeException("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||
}
|
||||
fetchTo = config.getFetchTo();
|
||||
}
|
||||
|
||||
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,
|
||||
name = "change originator",
|
||||
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. " +
|
||||
"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.",
|
||||
"If multiple related entities are found, only first entity is used as new originator, other entities are discarded.<br/>" +
|
||||
"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"},
|
||||
configDirective = "tbTransformationNodeChangeOriginatorConfig",
|
||||
icon = "find_replace"
|
||||
|
||||
@ -21,59 +21,63 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.RuleNode;
|
||||
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.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.TRANSFORMATION,
|
||||
name = "copy keys",
|
||||
name = "copy key-values",
|
||||
version = 1,
|
||||
configClazz = TbCopyKeysNodeConfiguration.class,
|
||||
nodeDescription = "Copies the msg or metadata keys with specified key names selected in the list",
|
||||
nodeDetails = "Will fetch fields values specified in list. If specified field is not part of msg or metadata fields it will be ignored." +
|
||||
"Returns transformed messages via <code>Success</code> chain",
|
||||
nodeDescription = "Copies key-values from message to message metadata or vice-versa.",
|
||||
nodeDetails = "Fetches key-values from message or message metadata based on the keys list specified in the configuration " +
|
||||
"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"},
|
||||
configDirective = "tbTransformationNodeCopyKeysConfig",
|
||||
icon = "content_copy"
|
||||
)
|
||||
public class TbCopyKeysNode implements TbNode {
|
||||
public class TbCopyKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
|
||||
|
||||
private TbCopyKeysNodeConfiguration config;
|
||||
private List<Pattern> patternKeys;
|
||||
private boolean fromMetadata;
|
||||
private TbMsgSource copyFrom;
|
||||
|
||||
@Override
|
||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||
this.config = TbNodeUtils.convert(configuration, TbCopyKeysNodeConfiguration.class);
|
||||
this.fromMetadata = config.isFromMetadata();
|
||||
this.patternKeys = new ArrayList<>();
|
||||
config.getKeys().forEach(key -> {
|
||||
this.patternKeys.add(Pattern.compile(key));
|
||||
});
|
||||
this.copyFrom = config.getCopyFrom();
|
||||
if (copyFrom == null) {
|
||||
throw new TbNodeException("CopyFrom can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||
}
|
||||
this.patternKeys = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
||||
TbMsgMetaData metaData = msg.getMetaData();
|
||||
var metaDataCopy = msg.getMetaData().copy();
|
||||
String msgData = msg.getData();
|
||||
boolean msgChanged = false;
|
||||
JsonNode dataNode = JacksonUtil.toJsonNode(msgData);
|
||||
if (dataNode.isObject()) {
|
||||
if (fromMetadata) {
|
||||
switch (copyFrom) {
|
||||
case METADATA:
|
||||
ObjectNode msgDataNode = (ObjectNode) dataNode;
|
||||
Map<String, String> metaDataMap = metaData.getData();
|
||||
Map<String, String> metaDataMap = metaDataCopy.getData();
|
||||
for (Map.Entry<String, String> entry : metaDataMap.entrySet()) {
|
||||
String keyData = entry.getKey();
|
||||
if (checkKey(keyData)) {
|
||||
@ -82,26 +86,33 @@ public class TbCopyKeysNode implements TbNode {
|
||||
}
|
||||
}
|
||||
msgData = JacksonUtil.toString(msgDataNode);
|
||||
} else {
|
||||
break;
|
||||
case DATA:
|
||||
Iterator<Map.Entry<String, JsonNode>> iteratorNode = dataNode.fields();
|
||||
while (iteratorNode.hasNext()) {
|
||||
Map.Entry<String, JsonNode> entry = iteratorNode.next();
|
||||
String keyData = entry.getKey();
|
||||
if (checkKey(keyData)) {
|
||||
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(TbMsg.transformMsg(msg, metaData, msgData));
|
||||
} else {
|
||||
ctx.tellSuccess(msg);
|
||||
ctx.tellSuccess(msgChanged ? TbMsg.transformMsg(msg, metaDataCopy, msgData) : msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getKeyToUpgradeFromVersionZero() {
|
||||
return "copyFrom";
|
||||
}
|
||||
|
||||
boolean checkKey(String key) {
|
||||
return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.transform;
|
||||
|
||||
import lombok.Data;
|
||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
@ -24,14 +25,14 @@ import java.util.Set;
|
||||
@Data
|
||||
public class TbCopyKeysNodeConfiguration implements NodeConfiguration<TbCopyKeysNodeConfiguration> {
|
||||
|
||||
private boolean fromMetadata;
|
||||
private TbMsgSource copyFrom;
|
||||
private Set<String> keys;
|
||||
|
||||
@Override
|
||||
public TbCopyKeysNodeConfiguration defaultConfiguration() {
|
||||
TbCopyKeysNodeConfiguration configuration = new TbCopyKeysNodeConfiguration();
|
||||
configuration.setKeys(Collections.emptySet());
|
||||
configuration.setFromMetadata(false);
|
||||
configuration.setCopyFrom(TbMsgSource.DATA);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
|
||||
@ -21,63 +21,69 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.RuleNode;
|
||||
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.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.TRANSFORMATION,
|
||||
name = "delete keys",
|
||||
name = "delete key-values",
|
||||
version = 1,
|
||||
configClazz = TbDeleteKeysNodeConfiguration.class,
|
||||
nodeDescription = "Removes keys from the msg data or metadata with the specified key names selected in the list",
|
||||
nodeDetails = "Will fetch fields (regex) values specified in list. If specified field (regex) is not part of msg " +
|
||||
"or metadata fields it will be ignored. Returns transformed messages via <code>Success</code> chain",
|
||||
nodeDescription = "Removes key-values from message or metadata.",
|
||||
nodeDetails = "Removes key-values from message or message metadata based on the keys list specified in the configuration. " +
|
||||
"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"},
|
||||
configDirective = "tbTransformationNodeDeleteKeysConfig",
|
||||
icon = "remove_circle"
|
||||
)
|
||||
public class TbDeleteKeysNode implements TbNode {
|
||||
public class TbDeleteKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
|
||||
|
||||
private TbDeleteKeysNodeConfiguration config;
|
||||
private List<Pattern> patternKeys;
|
||||
private boolean fromMetadata;
|
||||
private TbMsgSource deleteFrom;
|
||||
|
||||
@Override
|
||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||
this.config = TbNodeUtils.convert(configuration, TbDeleteKeysNodeConfiguration.class);
|
||||
this.fromMetadata = config.isFromMetadata();
|
||||
this.patternKeys = new ArrayList<>();
|
||||
config.getKeys().forEach(key -> {
|
||||
this.patternKeys.add(Pattern.compile(key));
|
||||
});
|
||||
this.deleteFrom = config.getDeleteFrom();
|
||||
if (deleteFrom == null) {
|
||||
throw new TbNodeException("DeleteFrom can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||
}
|
||||
this.patternKeys = config.getKeys().stream().map(Pattern::compile).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
||||
TbMsgMetaData metaData = msg.getMetaData();
|
||||
TbMsgMetaData metaDataCopy = msg.getMetaData().copy();
|
||||
String msgData = msg.getData();
|
||||
List<String> keysToDelete = new ArrayList<>();
|
||||
if (fromMetadata) {
|
||||
Map<String, String> metaDataMap = metaData.getData();
|
||||
switch (deleteFrom) {
|
||||
case METADATA:
|
||||
Map<String, String> metaDataMap = metaDataCopy.getData();
|
||||
metaDataMap.forEach((keyMetaData, valueMetaData) -> {
|
||||
if (checkKey(keyMetaData)) {
|
||||
keysToDelete.add(keyMetaData);
|
||||
}
|
||||
});
|
||||
keysToDelete.forEach(metaDataMap::remove);
|
||||
metaData = new TbMsgMetaData(metaDataMap);
|
||||
} else {
|
||||
metaDataCopy = new TbMsgMetaData(metaDataMap);
|
||||
break;
|
||||
case DATA:
|
||||
JsonNode dataNode = JacksonUtil.toJsonNode(msgData);
|
||||
if (dataNode.isObject()) {
|
||||
ObjectNode msgDataObject = (ObjectNode) dataNode;
|
||||
@ -90,15 +96,21 @@ public class TbDeleteKeysNode implements TbNode {
|
||||
msgDataObject.remove(keysToDelete);
|
||||
msgData = JacksonUtil.toString(msgDataObject);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log.debug("Unexpected DeleteFrom value: {}. Allowed values: {}", deleteFrom, TbMsgSource.values());
|
||||
break;
|
||||
}
|
||||
if (keysToDelete.isEmpty()) {
|
||||
ctx.tellSuccess(msg);
|
||||
} else {
|
||||
ctx.tellSuccess(TbMsg.transformMsg(msg, metaData, msgData));
|
||||
ctx.tellSuccess(keysToDelete.isEmpty() ? msg : TbMsg.transformMsg(msg, metaDataCopy, msgData));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getKeyToUpgradeFromVersionZero() {
|
||||
return "deleteFrom";
|
||||
}
|
||||
|
||||
boolean checkKey(String key) {
|
||||
return patternKeys.stream().anyMatch(pattern -> pattern.matcher(key).matches());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.transform;
|
||||
|
||||
import lombok.Data;
|
||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
@ -24,14 +25,14 @@ import java.util.Set;
|
||||
@Data
|
||||
public class TbDeleteKeysNodeConfiguration implements NodeConfiguration<TbDeleteKeysNodeConfiguration> {
|
||||
|
||||
private boolean fromMetadata;
|
||||
private TbMsgSource deleteFrom;
|
||||
private Set<String> keys;
|
||||
|
||||
@Override
|
||||
public TbDeleteKeysNodeConfiguration defaultConfiguration() {
|
||||
TbDeleteKeysNodeConfiguration configuration = new TbDeleteKeysNodeConfiguration();
|
||||
configuration.setKeys(Collections.emptySet());
|
||||
configuration.setFromMetadata(false);
|
||||
configuration.setDeleteFrom(TbMsgSource.DATA);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
|
||||
@ -38,10 +38,10 @@ import java.util.concurrent.ExecutionException;
|
||||
name = "json path",
|
||||
configClazz = TbJsonPathNodeConfiguration.class,
|
||||
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/>"
|
||||
+ "<b>'$'</b> represents the root object or array. <br/>"
|
||||
+ "If JSONPath expression evaluation failed, incoming message routes via <code>Failure</code> chain, "
|
||||
+ "otherwise <code>Success</code> chain is used.",
|
||||
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/>" +
|
||||
"If JSONPath expression evaluation failed, incoming message routes via <code>Failure</code> chain.<br><br>" +
|
||||
"Output connections: <code>Success</code>, <code>Failure</code>.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
icon = "functions",
|
||||
configDirective = "tbTransformationNodeJsonPathConfig"
|
||||
|
||||
@ -21,14 +21,15 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.RuleNode;
|
||||
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.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@ -36,34 +37,43 @@ import java.util.concurrent.ExecutionException;
|
||||
@RuleNode(
|
||||
type = ComponentType.TRANSFORMATION,
|
||||
name = "rename keys",
|
||||
version = 1,
|
||||
configClazz = TbRenameKeysNodeConfiguration.class,
|
||||
nodeDescription = "Renames msg data or metadata keys 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." +
|
||||
" Returns transformed messages via <code>Success</code> chain",
|
||||
nodeDescription = "Renames message or message metadata key names to the new key names selected in the key mapping.",
|
||||
nodeDetails = "If the key name that is selected in the key mapping is missed in the " +
|
||||
"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"},
|
||||
configDirective = "tbTransformationNodeRenameKeysConfig",
|
||||
icon = "find_replace"
|
||||
)
|
||||
public class TbRenameKeysNode implements TbNode {
|
||||
public class TbRenameKeysNode extends TbAbstractTransformNodeWithTbMsgSource {
|
||||
|
||||
private TbRenameKeysNodeConfiguration config;
|
||||
private Map<String, String> renameKeysMapping;
|
||||
private boolean fromMetadata;
|
||||
private TbMsgSource renameIn;
|
||||
|
||||
@Override
|
||||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
|
||||
this.config = TbNodeUtils.convert(configuration, TbRenameKeysNodeConfiguration.class);
|
||||
this.renameIn = config.getRenameIn();
|
||||
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
|
||||
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
|
||||
TbMsgMetaData metaData = msg.getMetaData();
|
||||
TbMsgMetaData metaDataCopy = msg.getMetaData().copy();
|
||||
String data = msg.getData();
|
||||
boolean msgChanged = false;
|
||||
if (fromMetadata) {
|
||||
Map<String, String> metaDataMap = metaData.getData();
|
||||
switch (renameIn) {
|
||||
case METADATA:
|
||||
Map<String, String> metaDataMap = metaDataCopy.getData();
|
||||
for (Map.Entry<String, String> entry : renameKeysMapping.entrySet()) {
|
||||
String nameKey = entry.getKey();
|
||||
if (metaDataMap.containsKey(nameKey)) {
|
||||
@ -72,8 +82,9 @@ public class TbRenameKeysNode implements TbNode {
|
||||
metaDataMap.remove(nameKey);
|
||||
}
|
||||
}
|
||||
metaData = new TbMsgMetaData(metaDataMap);
|
||||
} else {
|
||||
metaDataCopy = new TbMsgMetaData(metaDataMap);
|
||||
break;
|
||||
case DATA:
|
||||
JsonNode dataNode = JacksonUtil.toJsonNode(data);
|
||||
if (dataNode.isObject()) {
|
||||
ObjectNode msgData = (ObjectNode) dataNode;
|
||||
@ -87,11 +98,17 @@ public class TbRenameKeysNode implements TbNode {
|
||||
}
|
||||
data = JacksonUtil.toString(msgData);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log.debug("Unexpected RenameIn value: {}. Allowed values: {}", renameIn, TbMsgSource.values());
|
||||
break;
|
||||
}
|
||||
if (msgChanged) {
|
||||
ctx.tellSuccess(TbMsg.transformMsg(msg, metaData, data));
|
||||
} else {
|
||||
ctx.tellSuccess(msg);
|
||||
ctx.tellSuccess(msgChanged ? TbMsg.transformMsg(msg, metaDataCopy, data) : msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getKeyToUpgradeFromVersionZero() {
|
||||
return "renameIn";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,20 +17,21 @@ package org.thingsboard.rule.engine.transform;
|
||||
|
||||
import lombok.Data;
|
||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class TbRenameKeysNodeConfiguration implements NodeConfiguration<TbRenameKeysNodeConfiguration> {
|
||||
|
||||
private boolean fromMetadata;
|
||||
private TbMsgSource renameIn;
|
||||
private Map<String, String> renameKeysMapping;
|
||||
|
||||
@Override
|
||||
public TbRenameKeysNodeConfiguration defaultConfiguration() {
|
||||
TbRenameKeysNodeConfiguration configuration = new TbRenameKeysNodeConfiguration();
|
||||
configuration.setRenameKeysMapping(Map.of("temp", "temperature"));
|
||||
configuration.setFromMetadata(false);
|
||||
configuration.setRenameKeysMapping(Map.of("temperatureCelsius", "temperature"));
|
||||
configuration.setRenameIn(TbMsgSource.DATA);
|
||||
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.TbNodeConfiguration;
|
||||
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.server.common.data.msg.TbNodeConnectionType;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.queue.RuleEngineException;
|
||||
@ -39,10 +39,11 @@ import java.util.concurrent.ExecutionException;
|
||||
type = ComponentType.TRANSFORMATION,
|
||||
name = "split array msg",
|
||||
configClazz = EmptyNodeConfiguration.class,
|
||||
nodeDescription = "Split array message into several msgs",
|
||||
nodeDetails = "Split the array fetched from the msg body. If the msg data is not a JSON array returns the "
|
||||
nodeDescription = "Split array message into several messages",
|
||||
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 "
|
||||
+ "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"},
|
||||
icon = "content_copy",
|
||||
configDirective = "tbNodeEmptyConfig"
|
||||
|
||||
@ -39,7 +39,8 @@ import java.util.List;
|
||||
"<code>msgType</code> - is a Message type.<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/>" +
|
||||
"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"},
|
||||
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.user.UserService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -119,7 +120,7 @@ public class TbGetCustomerAttributeNodeTest {
|
||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
@ -57,6 +57,7 @@ import org.thingsboard.server.dao.edge.EdgeService;
|
||||
import org.thingsboard.server.dao.entityview.EntityViewService;
|
||||
import org.thingsboard.server.dao.user.UserService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
@ -127,7 +128,7 @@ public class TbGetCustomerDetailsNodeTest {
|
||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
@ -40,6 +40,7 @@ import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.device.DeviceService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -86,7 +87,7 @@ public class TbGetOriginatorFieldsNodeTest {
|
||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
@ -127,7 +127,7 @@ public class TbGetRelatedAttributeNodeTest {
|
||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -99,7 +100,7 @@ public class TbGetTenantAttributeNodeTest {
|
||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.dao.tenant.TenantService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@ -96,7 +97,7 @@ public class TbGetTenantDetailsNodeTest {
|
||||
var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration));
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.thingsboard.rule.engine.transform;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.TbNodeConfiguration;
|
||||
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.EntityId;
|
||||
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.TbMsgMetaData;
|
||||
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
||||
@ -37,6 +40,8 @@ import java.util.Set;
|
||||
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.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@ -59,7 +64,7 @@ public class TbCopyKeysNodeTest {
|
||||
ctx = mock(TbContext.class);
|
||||
config = new TbCopyKeysNodeConfiguration().defaultConfiguration();
|
||||
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));
|
||||
node = spy(new TbCopyKeysNode());
|
||||
node.init(ctx, nodeConfiguration);
|
||||
@ -74,7 +79,7 @@ public class TbCopyKeysNodeTest {
|
||||
void givenDefaultConfig_whenVerify_thenOK() {
|
||||
TbCopyKeysNodeConfiguration defaultConfig = new TbCopyKeysNodeConfiguration().defaultConfiguration();
|
||||
assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet());
|
||||
assertThat(defaultConfig.isFromMetadata()).isEqualTo(false);
|
||||
assertThat(defaultConfig.getCopyFrom()).isEqualTo(TbMsgSource.DATA);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -95,7 +100,7 @@ public class TbCopyKeysNodeTest {
|
||||
|
||||
@Test
|
||||
void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception {
|
||||
config.setFromMetadata(false);
|
||||
config.setCopyFrom(TbMsgSource.DATA);
|
||||
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||
node.init(ctx, nodeConfiguration);
|
||||
|
||||
@ -149,6 +154,20 @@ public class TbCopyKeysNodeTest {
|
||||
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) {
|
||||
final Map<String, String> mdMap = Map.of(
|
||||
"TestKey_1", "Test",
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.thingsboard.rule.engine.transform;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.TbNodeConfiguration;
|
||||
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.EntityId;
|
||||
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.TbMsgMetaData;
|
||||
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
||||
@ -37,6 +40,8 @@ import java.util.Set;
|
||||
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.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@ -59,7 +64,7 @@ public class TbDeleteKeysNodeTest {
|
||||
ctx = mock(TbContext.class);
|
||||
config = new TbDeleteKeysNodeConfiguration().defaultConfiguration();
|
||||
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));
|
||||
node = spy(new TbDeleteKeysNode());
|
||||
node.init(ctx, nodeConfiguration);
|
||||
@ -74,7 +79,7 @@ public class TbDeleteKeysNodeTest {
|
||||
void givenDefaultConfig_whenVerify_thenOK() {
|
||||
TbDeleteKeysNodeConfiguration defaultConfig = new TbDeleteKeysNodeConfiguration().defaultConfiguration();
|
||||
assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptySet());
|
||||
assertThat(defaultConfig.isFromMetadata()).isEqualTo(false);
|
||||
assertThat(defaultConfig.getDeleteFrom()).isEqualTo(TbMsgSource.DATA);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -95,7 +100,7 @@ public class TbDeleteKeysNodeTest {
|
||||
|
||||
@Test
|
||||
void givenMsgFromMsg_whenOnMsg_thenVerifyOutput() throws Exception {
|
||||
config.setFromMetadata(false);
|
||||
config.setDeleteFrom(TbMsgSource.DATA);
|
||||
nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||
node.init(ctx, nodeConfiguration);
|
||||
|
||||
@ -133,6 +138,20 @@ public class TbDeleteKeysNodeTest {
|
||||
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) {
|
||||
final Map<String, String> mdMap = Map.of(
|
||||
"TestKey_1", "Test",
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.thingsboard.rule.engine.transform;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.TbNodeConfiguration;
|
||||
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.EntityId;
|
||||
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.TbMsgMetaData;
|
||||
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
|
||||
@ -35,6 +38,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.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@ -70,8 +75,8 @@ public class TbRenameKeysNodeTest {
|
||||
@Test
|
||||
void givenDefaultConfig_whenVerify_thenOK() {
|
||||
TbRenameKeysNodeConfiguration defaultConfig = new TbRenameKeysNodeConfiguration().defaultConfiguration();
|
||||
assertThat(defaultConfig.getRenameKeysMapping()).isEqualTo(Map.of("temp", "temperature"));
|
||||
assertThat(defaultConfig.isFromMetadata()).isEqualTo(false);
|
||||
assertThat(defaultConfig.getRenameKeysMapping()).isEqualTo(Map.of("temperatureCelsius", "temperature"));
|
||||
assertThat(defaultConfig.getRenameIn()).isEqualTo(TbMsgSource.DATA);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -95,7 +100,7 @@ public class TbRenameKeysNodeTest {
|
||||
void givenMetadata_whenOnMsg_thenVerifyOutput() throws Exception {
|
||||
config = new TbRenameKeysNodeConfiguration().defaultConfiguration();
|
||||
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));
|
||||
node.init(ctx, nodeConfiguration);
|
||||
|
||||
@ -148,6 +153,20 @@ public class TbRenameKeysNodeTest {
|
||||
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) {
|
||||
final Map<String, String> mdMap = Map.of(
|
||||
"TestKey_1", "Test",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user