From 5bb70d84af49781f91be85c84bcd4072710d246c Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 4 Sep 2023 16:51:41 +0200 Subject: [PATCH] TbMsgAttributesNode implements TbVersionedNode with upgrade method and tests from version 0 --- .../engine/telemetry/TbMsgAttributesNode.java | 23 +++++- .../telemetry/TbMsgAttributesNodeTest.java | 73 +++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java index c63af3262d..79cbf87274 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java @@ -15,6 +15,8 @@ */ package org.thingsboard.rule.engine.telemetry; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -26,11 +28,13 @@ 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.TbVersionedNode; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.transport.adaptor.JsonConverter; @@ -51,6 +55,7 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R type = ComponentType.ACTION, name = "save attributes", configClazz = TbMsgAttributesNodeConfiguration.class, + version = 1, nodeDescription = "Saves attributes data", nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type. " + "If upsert(update/insert) operation is completed successfully rule node will send the incoming message via Success chain, otherwise, Failure chain is used. " + @@ -61,8 +66,9 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R configDirective = "tbActionNodeAttributesConfig", icon = "file_upload" ) -public class TbMsgAttributesNode implements TbNode { +public class TbMsgAttributesNode implements TbNode, TbVersionedNode { + static final String UPDATE_ATTRIBUTES_ON_VALUE_CHANGE_KEY = "updateAttributesOnValueChange"; private TbMsgAttributesNodeConfiguration config; @Override @@ -160,4 +166,19 @@ public class TbMsgAttributesNode implements TbNode { return config.getScope(); } + @Override + public TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException { + boolean hasChanges = false; + switch (fromVersion) { + case 0: + if (!oldConfiguration.has(UPDATE_ATTRIBUTES_ON_VALUE_CHANGE_KEY)) { + hasChanges = true; + ((ObjectNode) oldConfiguration).put(UPDATE_ATTRIBUTES_ON_VALUE_CHANGE_KEY, false); + } + break; + default: + } + return new TbPair<>(hasChanges, oldConfiguration); + } + } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java new file mode 100644 index 0000000000..28c762c107 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNodeTest.java @@ -0,0 +1,73 @@ +/** + * 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.telemetry; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.util.TbPair; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.willCallRealMethod; +import static org.mockito.Mockito.mock; + +@Slf4j +class TbMsgAttributesNodeTest { + + @Test + void testUpgrade_fromVersion0() throws TbNodeException { + final String updateAttributesOnValueChangeKey = "updateAttributesOnValueChange"; + TbMsgAttributesNode node = mock(TbMsgAttributesNode.class); + willCallRealMethod().given(node).upgrade(anyInt(), any()); + + ObjectNode jsonNode = (ObjectNode) JacksonUtil.valueToTree(new TbMsgAttributesNodeConfiguration().defaultConfiguration()); + jsonNode.remove(updateAttributesOnValueChangeKey); + assertThat(jsonNode.has(updateAttributesOnValueChangeKey)).as("pre condition has no " + updateAttributesOnValueChangeKey).isFalse(); + + TbPair upgradeResult = node.upgrade(0, jsonNode); + + ObjectNode resultNode = (ObjectNode) upgradeResult.getSecond(); + assertThat(upgradeResult.getFirst()).as("upgrade result has changes").isTrue(); + assertThat(resultNode.has(updateAttributesOnValueChangeKey)).as("upgrade result has key " + updateAttributesOnValueChangeKey).isTrue(); + assertThat(resultNode.get(updateAttributesOnValueChangeKey).asBoolean()).as("upgrade result value [false] for key " + updateAttributesOnValueChangeKey).isFalse(); + } + + @Test + void testUpgrade_fromVersion0_alreadyHasUpdateAttributesOnValueChange() throws TbNodeException { + final String updateAttributesOnValueChangeKey = "updateAttributesOnValueChange"; + TbMsgAttributesNode node = mock(TbMsgAttributesNode.class); + willCallRealMethod().given(node).upgrade(anyInt(), any()); + + ObjectNode jsonNode = (ObjectNode) JacksonUtil.valueToTree(new TbMsgAttributesNodeConfiguration().defaultConfiguration()); + jsonNode.remove(updateAttributesOnValueChangeKey); + jsonNode.put(updateAttributesOnValueChangeKey, true); + assertThat(jsonNode.has(updateAttributesOnValueChangeKey)).as("pre condition has no " + updateAttributesOnValueChangeKey).isTrue(); + assertThat(jsonNode.get(updateAttributesOnValueChangeKey).asBoolean()).as("pre condition has [true] for key " + updateAttributesOnValueChangeKey).isTrue(); + + TbPair upgradeResult = node.upgrade(0, jsonNode); + + ObjectNode resultNode = (ObjectNode) upgradeResult.getSecond(); + assertThat(upgradeResult.getFirst()).as("upgrade result has changes").isFalse(); + assertThat(resultNode.has(updateAttributesOnValueChangeKey)).as("upgrade result has key " + updateAttributesOnValueChangeKey).isTrue(); + assertThat(resultNode.get(updateAttributesOnValueChangeKey).asBoolean()).as("upgrade result value [true] for key " + updateAttributesOnValueChangeKey).isTrue(); + } + +}