added tests for the device attributes node
This commit is contained in:
parent
633411f9e1
commit
83308a68d6
@ -15,20 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.rule.engine.metadata;
|
package org.thingsboard.rule.engine.metadata;
|
||||||
|
|
||||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
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;
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.thingsboard.common.util.AbstractListeningExecutor;
|
import org.thingsboard.common.util.AbstractListeningExecutor;
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
|
import org.thingsboard.rule.engine.AbstractRuleNodeUpgradeTest;
|
||||||
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.util.TbMsgSource;
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
@ -43,7 +44,6 @@ import org.thingsboard.server.common.data.kv.JsonDataEntry;
|
|||||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
||||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||||
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.dao.attributes.AttributesService;
|
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||||
@ -51,25 +51,26 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
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.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
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.lenient;
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.timeout;
|
import static org.mockito.Mockito.timeout;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class TbGetAttributesNodeTest {
|
public class TbGetAttributesNodeTest extends AbstractRuleNodeUpgradeTest {
|
||||||
|
|
||||||
private static final EntityId ORIGINATOR = new DeviceId(Uuids.timeBased());
|
private final EntityId ORIGINATOR_ID = new DeviceId(UUID.fromString("965f2975-787a-4f21-87e6-9aa4738186ff"));
|
||||||
private static final TenantId TENANT_ID = TenantId.fromUUID(Uuids.timeBased());
|
private final TenantId TENANT_ID = TenantId.fromUUID(UUID.fromString("befd3239-79b8-4263-a8d1-95b69f44f798"));
|
||||||
private AbstractListeningExecutor dbExecutor;
|
private AbstractListeningExecutor dbExecutor;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@ -84,6 +85,8 @@ public class TbGetAttributesNodeTest {
|
|||||||
private List<String> sharedAttributes;
|
private List<String> sharedAttributes;
|
||||||
private List<String> tsKeys;
|
private List<String> tsKeys;
|
||||||
private long ts;
|
private long ts;
|
||||||
|
|
||||||
|
@Spy
|
||||||
private TbGetAttributesNode node;
|
private TbGetAttributesNode node;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@ -107,16 +110,16 @@ public class TbGetAttributesNodeTest {
|
|||||||
tsKeys = List.of("temperature", "humidity", "unknown");
|
tsKeys = List.of("temperature", "humidity", "unknown");
|
||||||
ts = System.currentTimeMillis();
|
ts = System.currentTimeMillis();
|
||||||
|
|
||||||
lenient().when(attributesServiceMock.find(TENANT_ID, ORIGINATOR, AttributeScope.CLIENT_SCOPE, clientAttributes))
|
lenient().when(attributesServiceMock.find(TENANT_ID, ORIGINATOR_ID, AttributeScope.CLIENT_SCOPE, clientAttributes))
|
||||||
.thenReturn(Futures.immediateFuture(getListAttributeKvEntry(clientAttributes, ts)));
|
.thenReturn(Futures.immediateFuture(getListAttributeKvEntry(clientAttributes, ts)));
|
||||||
|
|
||||||
lenient().when(attributesServiceMock.find(TENANT_ID, ORIGINATOR, AttributeScope.SERVER_SCOPE, serverAttributes))
|
lenient().when(attributesServiceMock.find(TENANT_ID, ORIGINATOR_ID, AttributeScope.SERVER_SCOPE, serverAttributes))
|
||||||
.thenReturn(Futures.immediateFuture(getListAttributeKvEntry(serverAttributes, ts)));
|
.thenReturn(Futures.immediateFuture(getListAttributeKvEntry(serverAttributes, ts)));
|
||||||
|
|
||||||
lenient().when(attributesServiceMock.find(TENANT_ID, ORIGINATOR, AttributeScope.SHARED_SCOPE, sharedAttributes))
|
lenient().when(attributesServiceMock.find(TENANT_ID, ORIGINATOR_ID, AttributeScope.SHARED_SCOPE, sharedAttributes))
|
||||||
.thenReturn(Futures.immediateFuture(getListAttributeKvEntry(sharedAttributes, ts)));
|
.thenReturn(Futures.immediateFuture(getListAttributeKvEntry(sharedAttributes, ts)));
|
||||||
|
|
||||||
lenient().when(timeseriesServiceMock.findLatest(TENANT_ID, ORIGINATOR, tsKeys))
|
lenient().when(timeseriesServiceMock.findLatest(TENANT_ID, ORIGINATOR_ID, tsKeys))
|
||||||
.thenReturn(Futures.immediateFuture(getListTsKvEntry(tsKeys, ts)));
|
.thenReturn(Futures.immediateFuture(getListTsKvEntry(tsKeys, ts)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +132,7 @@ public class TbGetAttributesNodeTest {
|
|||||||
public void givenFetchAttributesToMetadata_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
public void givenFetchAttributesToMetadata_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
node = initNode(TbMsgSource.METADATA, false, false);
|
node = initNode(TbMsgSource.METADATA, false, false);
|
||||||
var msg = getTbMsg(ORIGINATOR);
|
var msg = getTbMsg(ORIGINATOR_ID);
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
node.onMsg(ctxMock, msg);
|
node.onMsg(ctxMock, msg);
|
||||||
@ -148,7 +151,7 @@ public class TbGetAttributesNodeTest {
|
|||||||
public void givenFetchLatestTimeseriesToMetadata_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
public void givenFetchLatestTimeseriesToMetadata_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
node = initNode(TbMsgSource.METADATA, true, false);
|
node = initNode(TbMsgSource.METADATA, true, false);
|
||||||
var msg = getTbMsg(ORIGINATOR);
|
var msg = getTbMsg(ORIGINATOR_ID);
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
node.onMsg(ctxMock, msg);
|
node.onMsg(ctxMock, msg);
|
||||||
@ -167,7 +170,7 @@ public class TbGetAttributesNodeTest {
|
|||||||
public void givenFetchAttributesToData_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
public void givenFetchAttributesToData_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
node = initNode(TbMsgSource.DATA, false, false);
|
node = initNode(TbMsgSource.DATA, false, false);
|
||||||
var msg = getTbMsg(ORIGINATOR);
|
var msg = getTbMsg(ORIGINATOR_ID);
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
node.onMsg(ctxMock, msg);
|
node.onMsg(ctxMock, msg);
|
||||||
@ -186,7 +189,7 @@ public class TbGetAttributesNodeTest {
|
|||||||
public void givenFetchLatestTimeseriesToData_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
public void givenFetchLatestTimeseriesToData_whenOnMsg_thenShouldTellSuccess() throws Exception {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
node = initNode(TbMsgSource.DATA, true, false);
|
node = initNode(TbMsgSource.DATA, true, false);
|
||||||
var msg = getTbMsg(ORIGINATOR);
|
var msg = getTbMsg(ORIGINATOR_ID);
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
node.onMsg(ctxMock, msg);
|
node.onMsg(ctxMock, msg);
|
||||||
@ -205,7 +208,7 @@ public class TbGetAttributesNodeTest {
|
|||||||
public void givenFetchAttributesToMetadata_whenOnMsg_thenShouldTellFailure() throws Exception {
|
public void givenFetchAttributesToMetadata_whenOnMsg_thenShouldTellFailure() throws Exception {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
node = initNode(TbMsgSource.METADATA, false, true);
|
node = initNode(TbMsgSource.METADATA, false, true);
|
||||||
var msg = getTbMsg(ORIGINATOR);
|
var msg = getTbMsg(ORIGINATOR_ID);
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
node.onMsg(ctxMock, msg);
|
node.onMsg(ctxMock, msg);
|
||||||
@ -224,7 +227,7 @@ public class TbGetAttributesNodeTest {
|
|||||||
public void givenFetchLatestTimeseriesToData_whenOnMsg_thenShouldTellFailure() throws Exception {
|
public void givenFetchLatestTimeseriesToData_whenOnMsg_thenShouldTellFailure() throws Exception {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
node = initNode(TbMsgSource.DATA, true, true);
|
node = initNode(TbMsgSource.DATA, true, true);
|
||||||
var msg = getTbMsg(ORIGINATOR);
|
var msg = getTbMsg(ORIGINATOR_ID);
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
node.onMsg(ctxMock, msg);
|
node.onMsg(ctxMock, msg);
|
||||||
@ -243,7 +246,7 @@ public class TbGetAttributesNodeTest {
|
|||||||
public void givenFetchLatestTimeseriesToDataAndDataIsNotJsonObject_whenOnMsg_thenException() throws Exception {
|
public void givenFetchLatestTimeseriesToDataAndDataIsNotJsonObject_whenOnMsg_thenException() throws Exception {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
node = initNode(TbMsgSource.DATA, true, true);
|
node = initNode(TbMsgSource.DATA, true, true);
|
||||||
var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY);
|
var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ORIGINATOR_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY);
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg));
|
var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg));
|
||||||
@ -253,56 +256,6 @@ public class TbGetAttributesNodeTest {
|
|||||||
assertThat(exception.getMessage()).isEqualTo("Message body is not an object!");
|
assertThat(exception.getMessage()).isEqualTo("Message body is not an object!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
|
||||||
var defaultConfig = new TbGetAttributesNodeConfiguration().defaultConfiguration();
|
|
||||||
var node = new TbGetAttributesNode();
|
|
||||||
String oldConfig = "{\"fetchToData\":false," +
|
|
||||||
"\"clientAttributeNames\":[]," +
|
|
||||||
"\"sharedAttributeNames\":[]," +
|
|
||||||
"\"serverAttributeNames\":[]," +
|
|
||||||
"\"latestTsKeyNames\":[]," +
|
|
||||||
"\"tellFailureIfAbsent\":true," +
|
|
||||||
"\"getLatestValueWithTs\":false}";
|
|
||||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
|
||||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
|
||||||
Assertions.assertTrue(upgrade.getFirst());
|
|
||||||
Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenOldConfigWithNoFetchToDataProperty_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
|
||||||
var defaultConfig = new TbGetAttributesNodeConfiguration().defaultConfiguration();
|
|
||||||
var node = new TbGetAttributesNode();
|
|
||||||
String oldConfig = "{\"clientAttributeNames\":[]," +
|
|
||||||
"\"sharedAttributeNames\":[]," +
|
|
||||||
"\"serverAttributeNames\":[]," +
|
|
||||||
"\"latestTsKeyNames\":[]," +
|
|
||||||
"\"tellFailureIfAbsent\":true," +
|
|
||||||
"\"getLatestValueWithTs\":false}";
|
|
||||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
|
||||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
|
||||||
Assertions.assertTrue(upgrade.getFirst());
|
|
||||||
Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenOldConfigWithNullFetchToDataProperty_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
|
||||||
var defaultConfig = new TbGetAttributesNodeConfiguration().defaultConfiguration();
|
|
||||||
var node = new TbGetAttributesNode();
|
|
||||||
String oldConfig = "{\"fetchToData\":null," +
|
|
||||||
"\"clientAttributeNames\":[]," +
|
|
||||||
"\"sharedAttributeNames\":[]," +
|
|
||||||
"\"serverAttributeNames\":[]," +
|
|
||||||
"\"latestTsKeyNames\":[]," +
|
|
||||||
"\"tellFailureIfAbsent\":true," +
|
|
||||||
"\"getLatestValueWithTs\":false}";
|
|
||||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
|
||||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
|
||||||
Assertions.assertTrue(upgrade.getFirst());
|
|
||||||
Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private TbMsg checkMsg(boolean checkSuccess) {
|
private TbMsg checkMsg(boolean checkSuccess) {
|
||||||
var msgCaptor = ArgumentCaptor.forClass(TbMsg.class);
|
var msgCaptor = ArgumentCaptor.forClass(TbMsg.class);
|
||||||
if (checkSuccess) {
|
if (checkSuccess) {
|
||||||
@ -421,4 +374,117 @@ public class TbGetAttributesNodeTest {
|
|||||||
return kvEntriesList;
|
return kvEntriesList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Stream<Arguments> givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() {
|
||||||
|
return Stream.of(
|
||||||
|
// config for version 1 with upgrade from version 0
|
||||||
|
Arguments.of(0,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"fetchToData":false,
|
||||||
|
"clientAttributeNames":[],
|
||||||
|
"sharedAttributeNames":[],
|
||||||
|
"serverAttributeNames":[],
|
||||||
|
"latestTsKeyNames":[],
|
||||||
|
"tellFailureIfAbsent":true,
|
||||||
|
"getLatestValueWithTs":false
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
true,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
// config for version 1 with upgrade from version 0 (old config with no fetchToData property)
|
||||||
|
Arguments.of(0,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"clientAttributeNames":[],
|
||||||
|
"sharedAttributeNames":[],"serverAttributeNames":[],
|
||||||
|
"latestTsKeyNames":[],
|
||||||
|
"tellFailureIfAbsent":true,
|
||||||
|
"getLatestValueWithTs":false
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
true,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
// config for version 1 with upgrade from version 0 (old config with null fetchToData property)
|
||||||
|
Arguments.of(0,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"fetchToData":null,
|
||||||
|
"clientAttributeNames":[],
|
||||||
|
"sharedAttributeNames":[],
|
||||||
|
"serverAttributeNames":[],
|
||||||
|
"latestTsKeyNames":[],
|
||||||
|
"tellFailureIfAbsent":true,
|
||||||
|
"getLatestValueWithTs":false
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
true,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
// config for version 1 with upgrade from version 1
|
||||||
|
Arguments.of(1,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
false,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TbNode getTestNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,68 +15,236 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.rule.engine.metadata;
|
package org.thingsboard.rule.engine.metadata;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.thingsboard.common.util.JacksonUtil;
|
import org.thingsboard.common.util.JacksonUtil;
|
||||||
import org.thingsboard.server.common.data.util.TbPair;
|
import org.thingsboard.common.util.ListeningExecutor;
|
||||||
|
import org.thingsboard.rule.engine.AbstractRuleNodeUpgradeTest;
|
||||||
|
import org.thingsboard.rule.engine.TestDbCallbackExecutor;
|
||||||
|
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.data.DeviceRelationsQuery;
|
||||||
|
import org.thingsboard.rule.engine.util.TbMsgSource;
|
||||||
|
import org.thingsboard.server.common.data.device.DeviceSearchQuery;
|
||||||
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
|
import org.thingsboard.server.common.data.msg.TbMsgType;
|
||||||
|
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||||
|
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||||
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
|
import org.thingsboard.server.dao.device.DeviceService;
|
||||||
|
|
||||||
public class TbGetDeviceAttrNodeTest {
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Test
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
var defaultConfig = new TbGetDeviceAttrNodeConfiguration().defaultConfiguration();
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
var node = new TbGetDeviceAttrNode();
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
String oldConfig = "{\"fetchToData\":false," +
|
import static org.mockito.BDDMockito.given;
|
||||||
"\"clientAttributeNames\":[]," +
|
import static org.mockito.BDDMockito.spy;
|
||||||
"\"sharedAttributeNames\":[]," +
|
import static org.mockito.BDDMockito.then;
|
||||||
"\"serverAttributeNames\":[]," +
|
|
||||||
"\"latestTsKeyNames\":[]," +
|
@ExtendWith(MockitoExtension.class)
|
||||||
"\"tellFailureIfAbsent\":true," +
|
public class TbGetDeviceAttrNodeTest extends AbstractRuleNodeUpgradeTest {
|
||||||
"\"getLatestValueWithTs\":false," +
|
|
||||||
"\"deviceRelationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1,\"relationType\":\"Contains\",\"deviceTypes\":[\"default\"]," +
|
private final TenantId TENANT_ID = new TenantId(UUID.fromString("5aea576c-66c4-4732-86b8-dc6bfcde7443"));
|
||||||
"\"fetchLastLevelOnly\":false}}";
|
private final DeviceId DEVICE_ID = new DeviceId(UUID.fromString("40b6b393-6ddf-47f9-973a-18550ca70384"));
|
||||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
private final ListeningExecutor executor = new TestDbCallbackExecutor();
|
||||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
|
||||||
Assertions.assertTrue(upgrade.getFirst());
|
|
||||||
Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass()));
|
private TbGetDeviceAttrNode node;
|
||||||
|
private TbGetDeviceAttrNodeConfiguration config;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TbContext ctxMock;
|
||||||
|
@Mock
|
||||||
|
private DeviceService deviceServiceMock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
node = spy(new TbGetDeviceAttrNode());
|
||||||
|
config = new TbGetDeviceAttrNodeConfiguration().defaultConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenOldConfigWithNoFetchToDataProperty_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
public void verifyDefaultConfig() {
|
||||||
var defaultConfig = new TbGetDeviceAttrNodeConfiguration().defaultConfiguration();
|
assertThat(config.getClientAttributeNames()).isEmpty();
|
||||||
var node = new TbGetDeviceAttrNode();
|
assertThat(config.getSharedAttributeNames()).isEmpty();
|
||||||
String oldConfig = "{\"clientAttributeNames\":[]," +
|
assertThat(config.getServerAttributeNames()).isEmpty();
|
||||||
"\"sharedAttributeNames\":[]," +
|
assertThat(config.getLatestTsKeyNames()).isEmpty();
|
||||||
"\"serverAttributeNames\":[]," +
|
assertThat(config.isTellFailureIfAbsent()).isTrue();
|
||||||
"\"latestTsKeyNames\":[]," +
|
assertThat(config.isGetLatestValueWithTs()).isFalse();
|
||||||
"\"tellFailureIfAbsent\":true," +
|
assertThat(config.getFetchTo()).isEqualTo(TbMsgSource.METADATA);
|
||||||
"\"getLatestValueWithTs\":false," +
|
|
||||||
"\"deviceRelationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1,\"relationType\":\"Contains\",\"deviceTypes\":[\"default\"]," +
|
var deviceRelationsQuery = new DeviceRelationsQuery();
|
||||||
"\"fetchLastLevelOnly\":false}}";
|
deviceRelationsQuery.setDirection(EntitySearchDirection.FROM);
|
||||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
deviceRelationsQuery.setMaxLevel(1);
|
||||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
deviceRelationsQuery.setRelationType(EntityRelation.CONTAINS_TYPE);
|
||||||
Assertions.assertTrue(upgrade.getFirst());
|
deviceRelationsQuery.setDeviceTypes(Collections.singletonList("default"));
|
||||||
Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass()));
|
|
||||||
|
assertThat(config.getDeviceRelationsQuery()).isEqualTo(deviceRelationsQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenOldConfigWithNullFetchToDataProperty_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception {
|
public void givenFetchToIsNull_whenInit_thenThrowsException() {
|
||||||
var defaultConfig = new TbGetDeviceAttrNodeConfiguration().defaultConfiguration();
|
config.setFetchTo(null);
|
||||||
var node = new TbGetDeviceAttrNode();
|
assertThatThrownBy(() -> node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config))))
|
||||||
String oldConfig = "{\"fetchToData\":null," +
|
.isInstanceOf(TbNodeException.class)
|
||||||
"\"clientAttributeNames\":[]," +
|
.hasMessage("FetchTo option can't be null! Allowed values: " + Arrays.toString(TbMsgSource.values()));
|
||||||
"\"sharedAttributeNames\":[]," +
|
}
|
||||||
"\"serverAttributeNames\":[]," +
|
|
||||||
"\"latestTsKeyNames\":[]," +
|
@Test
|
||||||
"\"tellFailureIfAbsent\":true," +
|
public void givenDeviceDoesNotExist_whenOnMsg_thenTellFailure() throws TbNodeException {
|
||||||
"\"getLatestValueWithTs\":false," +
|
node.init(ctxMock, new TbNodeConfiguration(JacksonUtil.valueToTree(config)));
|
||||||
"\"deviceRelationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1,\"relationType\":\"Contains\",\"deviceTypes\":[\"default\"]," +
|
|
||||||
"\"fetchLastLevelOnly\":false}}";
|
given(ctxMock.getDeviceService()).willReturn(deviceServiceMock);
|
||||||
JsonNode configJson = JacksonUtil.toJsonNode(oldConfig);
|
given(ctxMock.getTenantId()).willReturn(TENANT_ID);
|
||||||
TbPair<Boolean, JsonNode> upgrade = node.upgrade(0, configJson);
|
given(deviceServiceMock.findDevicesByQuery(any(TenantId.class), any(DeviceSearchQuery.class))).willReturn(Futures.immediateFuture(Collections.emptyList()));
|
||||||
Assertions.assertTrue(upgrade.getFirst());
|
given(ctxMock.getDbCallbackExecutor()).willReturn(executor);
|
||||||
Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass()));
|
|
||||||
|
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT);
|
||||||
|
node.onMsg(ctxMock, msg);
|
||||||
|
|
||||||
|
ArgumentCaptor<Throwable> actualException = ArgumentCaptor.forClass(Throwable.class);
|
||||||
|
then(ctxMock).should().tellFailure(eq(msg), actualException.capture());
|
||||||
|
assertThat(actualException.getValue())
|
||||||
|
.isInstanceOf(NoSuchElementException.class)
|
||||||
|
.hasMessage("Failed to find related device to message originator using relation query specified in the configuration!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<Arguments> givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() {
|
||||||
|
return Stream.of(
|
||||||
|
// config for version 1 with upgrade from version 0
|
||||||
|
Arguments.of(0,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"fetchToData":false,
|
||||||
|
"clientAttributeNames":[],
|
||||||
|
"sharedAttributeNames":[],
|
||||||
|
"serverAttributeNames":[],
|
||||||
|
"latestTsKeyNames":[],
|
||||||
|
"tellFailureIfAbsent":true,
|
||||||
|
"getLatestValueWithTs":false,
|
||||||
|
"deviceRelationsQuery":{"direction":"FROM","maxLevel":1,"relationType":"Contains","deviceTypes":["default"],"fetchLastLevelOnly":false}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
true,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"deviceRelationsQuery": {"direction": "FROM","maxLevel": 1, "relationType": "Contains","deviceTypes": ["default"],"fetchLastLevelOnly": false},
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
// config for version 1 with upgrade from version 0 (old config with no fetchToData property)
|
||||||
|
Arguments.of(0,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"clientAttributeNames":[],
|
||||||
|
"sharedAttributeNames":[],
|
||||||
|
"serverAttributeNames":[],
|
||||||
|
"latestTsKeyNames":[],
|
||||||
|
"tellFailureIfAbsent":true,
|
||||||
|
"getLatestValueWithTs":false,
|
||||||
|
"deviceRelationsQuery":{"direction":"FROM","maxLevel":1,"relationType":"Contains","deviceTypes":["default"],"fetchLastLevelOnly":false}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
true,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"deviceRelationsQuery": {"direction": "FROM","maxLevel": 1, "relationType": "Contains","deviceTypes": ["default"],"fetchLastLevelOnly": false},
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
// config for version 1 with upgrade from version 0 (old config with null fetchToData property)
|
||||||
|
Arguments.of(0,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"fetchToData":null,
|
||||||
|
"clientAttributeNames":[],
|
||||||
|
"sharedAttributeNames":[],
|
||||||
|
"serverAttributeNames":[],
|
||||||
|
"latestTsKeyNames":[],
|
||||||
|
"tellFailureIfAbsent":true,
|
||||||
|
"getLatestValueWithTs":false,
|
||||||
|
"deviceRelationsQuery":{"direction":"FROM","maxLevel":1,"relationType":"Contains","deviceTypes":["default"],"fetchLastLevelOnly":false}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
true,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"deviceRelationsQuery": {"direction": "FROM","maxLevel": 1, "relationType": "Contains","deviceTypes": ["default"],"fetchLastLevelOnly": false},
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
// config for version 1 with upgrade from version 1
|
||||||
|
Arguments.of(1,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"deviceRelationsQuery": {"direction": "FROM","maxLevel": 1, "relationType": "Contains","deviceTypes": ["default"],"fetchLastLevelOnly": false},
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
false,
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"deviceRelationsQuery": {"direction": "FROM","maxLevel": 1, "relationType": "Contains","deviceTypes": ["default"],"fetchLastLevelOnly": false},
|
||||||
|
"tellFailureIfAbsent": true,
|
||||||
|
"fetchTo": "METADATA",
|
||||||
|
"clientAttributeNames": [],
|
||||||
|
"sharedAttributeNames": [],
|
||||||
|
"serverAttributeNames": [],
|
||||||
|
"latestTsKeyNames": [],
|
||||||
|
"getLatestValueWithTs": false
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TbNode getTestNode() {
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user