From 9c740e147d4bc9c8e60604db28c17c523066aed4 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Tue, 9 Apr 2024 13:46:41 +0300 Subject: [PATCH 1/6] added tests for copy to view node --- .../TbCopyAttributesToEntityViewNodeTest.java | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java new file mode 100644 index 0000000000..a08872ba02 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java @@ -0,0 +1,224 @@ +/** + * Copyright © 2016-2024 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.action; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.AttributeScope; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.objects.AttributesEntityView; +import org.thingsboard.server.common.data.objects.TelemetryEntityView; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.entityview.EntityViewService; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.refEq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; + +@ExtendWith(MockitoExtension.class) +public class TbCopyAttributesToEntityViewNodeTest { + + private final TenantId TENANT_ID = new TenantId(UUID.fromString("9fdb1f05-dc66-4960-9263-ae195f1b4533")); + private final DeviceId DEVICE_ID = new DeviceId(UUID.fromString("1d453dc9-9333-476a-a51f-093cf2176e59")); + + private TbCopyAttributesToEntityViewNode node; + private EmptyNodeConfiguration config; + + @Mock + private TbContext ctxMock; + @Mock + private EntityViewService entityViewServiceMock; + @Mock + private RuleEngineTelemetryService telemetryServiceMock; + + @BeforeEach + void setUp() throws TbNodeException { + node = new TbCopyAttributesToEntityViewNode(); + config = new EmptyNodeConfiguration().defaultConfiguration(); + var configuration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + node.init(ctxMock, configuration); + } + + @Test + public void givenExistingAttributes_whenOnMsg_thenCopyAttributeValuesToView() { + EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); + EntityView entityView = new EntityView(entityViewId); + entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); + entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); + AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); + entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + + TbMsg msg = TbMsg.newMsg( + TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + "{\"attribute1\": 100, \"attribute2\": \"value2\"}"); + + when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) + .thenReturn(Futures.immediateFuture(List.of(entityView))); + when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); + doAnswer(invocation -> { + FutureCallback callback = invocation.getArgument(4); + callback.onSuccess(null); + return null; + }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); + doAnswer(invocation -> { + TbMsg newMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); + return newMsg; + }).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); + + node.onMsg(ctxMock, msg); + + verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); + verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); + verify(ctxMock).ack(eq(msg)); + TbMsg expectedNewMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); + verify(ctxMock).enqueueForTellNext(refEq(expectedNewMsg, "ts", "id", "ctx"), eq("Success")); + } + + @Test + void givenExistingAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributeValuesFromView() { + EntityViewId entityViewId = EntityViewId.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925"); + EntityView entityView = new EntityView(entityViewId); + entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); + entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); + AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); + entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + + TbMsg msg = TbMsg.newMsg( + ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + "{\"attributes\": [\"attribute1\"]}"); + + when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) + .thenReturn(Futures.immediateFuture(List.of(entityView))); + when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); + doAnswer(invocation -> { + FutureCallback callback = invocation.getArgument(4); + callback.onSuccess(null); + return null; + }).when(telemetryServiceMock).deleteAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); + doAnswer(invocation -> { + TbMsg newMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); + return newMsg; + }).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); + + node.onMsg(ctxMock, msg); + + verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); + verify(telemetryServiceMock).deleteAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); + verify(ctxMock).ack(eq(msg)); + TbMsg expectedNewMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); + verify(ctxMock).enqueueForTellNext(refEq(expectedNewMsg, "ts", "id", "ctx"), eq("Success")); + } + + @Test + void givenAttributesDateOutOfStartDateAndEndDate_whenOnMsg_thenThrowsException() { + EntityViewId entityViewId = EntityViewId.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925"); + EntityView entityView = new EntityView(entityViewId); + entityView.setStartTimeMs(Instant.now().minus(2, ChronoUnit.DAYS).toEpochMilli()); + entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); + AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); + entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + + when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) + .thenReturn(Futures.immediateFuture(List.of(entityView))); + + TbMsg msg = TbMsg.newMsg( + ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + "{\"attributes\": [\"attribute1\"]}"); + + node.onMsg(ctxMock, msg); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctxMock).tellFailure(eq(msg), captor.capture()); + } + + @Test + void givenEmptyMetadata_whenOnMsg_thenThrowsException() { + TbMsg msg = TbMsg.newMsg( + ATTRIBUTES_UPDATED, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + + node.onMsg(ctxMock, msg); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctxMock).tellFailure(eq(msg), captor.capture()); + Throwable throwable = captor.getValue(); + assertThat(throwable.getClass()).isEqualTo(IllegalArgumentException.class); + String expectedExceptionMessage = "java.lang.IllegalArgumentException: Message metadata is empty"; + assertThat(throwable.toString()).isEqualTo(expectedExceptionMessage); + } + + @ParameterizedTest + @EnumSource(TbMsgType.class) + public void givenUnsupportedMsgType_whenOnMsg_thenTellFailure(TbMsgType msgType) { + TbMsg msg = TbMsg.newMsg( + msgType, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + + if (msg.isTypeOneOf(ATTRIBUTES_UPDATED, ATTRIBUTES_DELETED, + ACTIVITY_EVENT, INACTIVITY_EVENT, POST_ATTRIBUTES_REQUEST)) { + return; + } + + node.onMsg(ctxMock, msg); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); + verify(ctxMock).tellFailure(eq(msg), captor.capture()); + Throwable throwable = captor.getValue(); + assertThat(throwable.getClass()).isEqualTo(IllegalArgumentException.class); + String expectedExceptionMessage = "java.lang.IllegalArgumentException: Unsupported msg type [" + msg.getType() + "]"; + assertThat(throwable.toString()).isEqualTo(expectedExceptionMessage); + } +} \ No newline at end of file From 5a3e16f28dddf3113564199a1a324c9dbde09045 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Wed, 10 Apr 2024 13:40:36 +0300 Subject: [PATCH 2/6] added test to check node when there are no matching attributes --- .../TbCopyAttributesToEntityViewNodeTest.java | 73 +++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java index a08872ba02..042f768d79 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java @@ -56,6 +56,7 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.refEq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; @@ -89,7 +90,7 @@ public class TbCopyAttributesToEntityViewNodeTest { } @Test - public void givenExistingAttributes_whenOnMsg_thenCopyAttributeValuesToView() { + public void givenExistingAttributes_whenOnMsg_thenCopyAttributesToView() { EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); EntityView entityView = new EntityView(entityViewId); entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); @@ -126,7 +127,7 @@ public class TbCopyAttributesToEntityViewNodeTest { } @Test - void givenExistingAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributeValuesFromView() { + public void givenExistingAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributesFromView() { EntityViewId entityViewId = EntityViewId.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925"); EntityView entityView = new EntityView(entityViewId); entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); @@ -163,7 +164,69 @@ public class TbCopyAttributesToEntityViewNodeTest { } @Test - void givenAttributesDateOutOfStartDateAndEndDate_whenOnMsg_thenThrowsException() { + public void givenNonMatchedAttributesAndMsgTypeIsAttributesDeleted_whenOnMsg_thenNoAttributesDeleteFromView() { + EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); + EntityView entityView = new EntityView(entityViewId); + entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); + entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); + AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); + entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + + TbMsg msg = TbMsg.newMsg( + TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + "{\"attributes\": [\"anotherAttribute\"]}"); + + when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) + .thenReturn(Futures.immediateFuture(List.of(entityView))); + + node.onMsg(ctxMock, msg); + + verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); + verify(ctxMock).ack(eq(msg)); + verify(ctxMock, never()).getTelemetryService(); + } + + @Test + public void givenNonMatchedAttributesAndMsgTypeIsPostAttributesRequest_whenOnMsg_thenCopyNoAttributesToView() { + EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); + EntityView entityView = new EntityView(entityViewId); + entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); + entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); + AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); + entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + + TbMsg msg = TbMsg.newMsg( + TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + "{\"attribute2\": \"value2\"}"); + + when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) + .thenReturn(Futures.immediateFuture(List.of(entityView))); + when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); + doAnswer(invocation -> { + FutureCallback callback = invocation.getArgument(4); + callback.onSuccess(null); + return null; + }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); + doAnswer(invocation -> { + TbMsg newMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); + return newMsg; + }).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); + + node.onMsg(ctxMock, msg); + + verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); + verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), eq(Collections.emptyList()), any(FutureCallback.class)); + verify(ctxMock).ack(eq(msg)); + TbMsg expectedNewMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); + verify(ctxMock).enqueueForTellNext(refEq(expectedNewMsg, "ts", "id", "ctx"), eq("Success")); + } + + @Test + public void givenAttributesValidityPeriodOutOfStartDateAndEndDate_whenOnMsg_thenThrowsException() { EntityViewId entityViewId = EntityViewId.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925"); EntityView entityView = new EntityView(entityViewId); entityView.setStartTimeMs(Instant.now().minus(2, ChronoUnit.DAYS).toEpochMilli()); @@ -187,7 +250,7 @@ public class TbCopyAttributesToEntityViewNodeTest { } @Test - void givenEmptyMetadata_whenOnMsg_thenThrowsException() { + public void givenEmptyMetadata_whenOnMsg_thenThrowsException() { TbMsg msg = TbMsg.newMsg( ATTRIBUTES_UPDATED, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); @@ -221,4 +284,4 @@ public class TbCopyAttributesToEntityViewNodeTest { String expectedExceptionMessage = "java.lang.IllegalArgumentException: Unsupported msg type [" + msg.getType() + "]"; assertThat(throwable.toString()).isEqualTo(expectedExceptionMessage); } -} \ No newline at end of file +} From 2a18f0c2b655b883744cde2995cf4da912fa5696 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 15 Apr 2024 18:36:13 +0300 Subject: [PATCH 3/6] moved creation of entity view to a separate method --- .../TbCopyAttributesToEntityViewNodeTest.java | 90 ++++++++----------- 1 file changed, 35 insertions(+), 55 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java index 042f768d79..952cc21c14 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.common.msg.TbMsg; @@ -54,7 +55,6 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.refEq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -70,6 +70,8 @@ public class TbCopyAttributesToEntityViewNodeTest { private final TenantId TENANT_ID = new TenantId(UUID.fromString("9fdb1f05-dc66-4960-9263-ae195f1b4533")); private final DeviceId DEVICE_ID = new DeviceId(UUID.fromString("1d453dc9-9333-476a-a51f-093cf2176e59")); + private final long FROM_DATE = Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(); + private final long TO_DATE = Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli(); private TbCopyAttributesToEntityViewNode node; private EmptyNodeConfiguration config; @@ -91,12 +93,8 @@ public class TbCopyAttributesToEntityViewNodeTest { @Test public void givenExistingAttributes_whenOnMsg_thenCopyAttributesToView() { - EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); - EntityView entityView = new EntityView(entityViewId); - entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); - AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); - entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + EntityView entityView = getEntityView(); + EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), @@ -112,28 +110,21 @@ public class TbCopyAttributesToEntityViewNodeTest { callback.onSuccess(null); return null; }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); - doAnswer(invocation -> { - TbMsg newMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); - return newMsg; - }).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); + TbMsg newMsg = TbMsg.newMsg(msg, msg.getQueueName(), msg.getRuleChainId(), msg.getRuleNodeId()); + doAnswer(invocation -> newMsg).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); verify(ctxMock).ack(eq(msg)); - TbMsg expectedNewMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); - verify(ctxMock).enqueueForTellNext(refEq(expectedNewMsg, "ts", "id", "ctx"), eq("Success")); + verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); } @Test public void givenExistingAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributesFromView() { - EntityViewId entityViewId = EntityViewId.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925"); - EntityView entityView = new EntityView(entityViewId); - entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); - AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); - entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + EntityView entityView = getEntityView(); + EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), @@ -149,28 +140,20 @@ public class TbCopyAttributesToEntityViewNodeTest { callback.onSuccess(null); return null; }).when(telemetryServiceMock).deleteAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); - doAnswer(invocation -> { - TbMsg newMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); - return newMsg; - }).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); + TbMsg newMsg = TbMsg.newMsg(msg, msg.getQueueName(), msg.getRuleChainId(), msg.getRuleNodeId()); + doAnswer(invocation -> newMsg).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); verify(telemetryServiceMock).deleteAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); verify(ctxMock).ack(eq(msg)); - TbMsg expectedNewMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); - verify(ctxMock).enqueueForTellNext(refEq(expectedNewMsg, "ts", "id", "ctx"), eq("Success")); + verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); } @Test public void givenNonMatchedAttributesAndMsgTypeIsAttributesDeleted_whenOnMsg_thenNoAttributesDeleteFromView() { - EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); - EntityView entityView = new EntityView(entityViewId); - entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); - AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); - entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + EntityView entityView = getEntityView(); TbMsg msg = TbMsg.newMsg( TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), @@ -190,12 +173,8 @@ public class TbCopyAttributesToEntityViewNodeTest { @Test public void givenNonMatchedAttributesAndMsgTypeIsPostAttributesRequest_whenOnMsg_thenCopyNoAttributesToView() { - EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); - EntityView entityView = new EntityView(entityViewId); - entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); - AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); - entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + EntityView entityView = getEntityView(); + EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), @@ -211,28 +190,23 @@ public class TbCopyAttributesToEntityViewNodeTest { callback.onSuccess(null); return null; }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); - doAnswer(invocation -> { - TbMsg newMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); - return newMsg; - }).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); + TbMsg newMsg = TbMsg.newMsg(msg, msg.getQueueName(), msg.getRuleChainId(), msg.getRuleNodeId()); + doAnswer(invocation -> newMsg).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), eq(Collections.emptyList()), any(FutureCallback.class)); verify(ctxMock).ack(eq(msg)); - TbMsg expectedNewMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), entityViewId, msg.getCustomerId(), msg.getMetaData(), msg.getData()); - verify(ctxMock).enqueueForTellNext(refEq(expectedNewMsg, "ts", "id", "ctx"), eq("Success")); + verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); } @Test - public void givenAttributesValidityPeriodOutOfStartDateAndEndDate_whenOnMsg_thenThrowsException() { + public void givenAttributesValidityPeriodOutOfStartDateAndEndDate_whenOnMsg_thenDoNothing() { EntityViewId entityViewId = EntityViewId.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925"); EntityView entityView = new EntityView(entityViewId); entityView.setStartTimeMs(Instant.now().minus(2, ChronoUnit.DAYS).toEpochMilli()); - entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); - entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + entityView.setEndTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); @@ -245,8 +219,8 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); - ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctxMock).tellFailure(eq(msg), captor.capture()); + verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); + verify(ctxMock).ack(eq(msg)); } @Test @@ -259,9 +233,7 @@ public class TbCopyAttributesToEntityViewNodeTest { ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); verify(ctxMock).tellFailure(eq(msg), captor.capture()); Throwable throwable = captor.getValue(); - assertThat(throwable.getClass()).isEqualTo(IllegalArgumentException.class); - String expectedExceptionMessage = "java.lang.IllegalArgumentException: Message metadata is empty"; - assertThat(throwable.toString()).isEqualTo(expectedExceptionMessage); + assertThat(throwable).isInstanceOf(IllegalArgumentException.class).hasMessage("Message metadata is empty"); } @ParameterizedTest @@ -280,8 +252,16 @@ public class TbCopyAttributesToEntityViewNodeTest { ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); verify(ctxMock).tellFailure(eq(msg), captor.capture()); Throwable throwable = captor.getValue(); - assertThat(throwable.getClass()).isEqualTo(IllegalArgumentException.class); - String expectedExceptionMessage = "java.lang.IllegalArgumentException: Unsupported msg type [" + msg.getType() + "]"; - assertThat(throwable.toString()).isEqualTo(expectedExceptionMessage); + assertThat(throwable).isInstanceOf(IllegalArgumentException.class).hasMessage("Unsupported msg type [" + msgType + "]"); + } + + private EntityView getEntityView() { + EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); + EntityView entityView = new EntityView(entityViewId); + entityView.setStartTimeMs(FROM_DATE); + entityView.setEndTimeMs(TO_DATE); + AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); + entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + return entityView; } } From 2f452e2193b08b76a3f2a9aea846bd111a69d28c Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 6 May 2024 09:27:39 +0300 Subject: [PATCH 4/6] used AttributesScope value names instead of strings --- .../action/TbCopyAttributesToEntityViewNodeTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java index 952cc21c14..2f7d681630 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java @@ -97,7 +97,7 @@ public class TbCopyAttributesToEntityViewNodeTest { EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( - TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attribute1\": 100, \"attribute2\": \"value2\"}"); when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); @@ -127,7 +127,7 @@ public class TbCopyAttributesToEntityViewNodeTest { EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( - ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attributes\": [\"attribute1\"]}"); when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); @@ -156,7 +156,7 @@ public class TbCopyAttributesToEntityViewNodeTest { EntityView entityView = getEntityView(); TbMsg msg = TbMsg.newMsg( - TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attributes\": [\"anotherAttribute\"]}"); when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); @@ -177,7 +177,7 @@ public class TbCopyAttributesToEntityViewNodeTest { EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( - TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attribute2\": \"value2\"}"); when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); @@ -214,7 +214,7 @@ public class TbCopyAttributesToEntityViewNodeTest { .thenReturn(Futures.immediateFuture(List.of(entityView))); TbMsg msg = TbMsg.newMsg( - ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", "CLIENT_SCOPE")), + ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attributes\": [\"attribute1\"]}"); node.onMsg(ctxMock, msg); From de7b6dddea10477a49d7967d44a6e435df67d285 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Tue, 28 May 2024 11:49:07 +0300 Subject: [PATCH 5/6] refactored tests --- .../TbCopyAttributesToEntityViewNodeTest.java | 70 +++++++------------ 1 file changed, 27 insertions(+), 43 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java index 2f7d681630..76b5b0f446 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java @@ -68,13 +68,10 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R @ExtendWith(MockitoExtension.class) public class TbCopyAttributesToEntityViewNodeTest { - private final TenantId TENANT_ID = new TenantId(UUID.fromString("9fdb1f05-dc66-4960-9263-ae195f1b4533")); + private final TenantId TENANT_ID = TenantId.fromUUID(UUID.fromString("9fdb1f05-dc66-4960-9263-ae195f1b4533")); private final DeviceId DEVICE_ID = new DeviceId(UUID.fromString("1d453dc9-9333-476a-a51f-093cf2176e59")); - private final long FROM_DATE = Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(); - private final long TO_DATE = Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli(); private TbCopyAttributesToEntityViewNode node; - private EmptyNodeConfiguration config; @Mock private TbContext ctxMock; @@ -86,7 +83,7 @@ public class TbCopyAttributesToEntityViewNodeTest { @BeforeEach void setUp() throws TbNodeException { node = new TbCopyAttributesToEntityViewNode(); - config = new EmptyNodeConfiguration().defaultConfiguration(); + var config = new EmptyNodeConfiguration().defaultConfiguration(); var configuration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); node.init(ctxMock, configuration); } @@ -94,16 +91,12 @@ public class TbCopyAttributesToEntityViewNodeTest { @Test public void givenExistingAttributes_whenOnMsg_thenCopyAttributesToView() { EntityView entityView = getEntityView(); - EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attribute1\": 100, \"attribute2\": \"value2\"}"); - when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) - .thenReturn(Futures.immediateFuture(List.of(entityView))); + mockEntityViewService(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { FutureCallback callback = invocation.getArgument(4); @@ -116,7 +109,7 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); + verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityView.getId()), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); } @@ -124,16 +117,12 @@ public class TbCopyAttributesToEntityViewNodeTest { @Test public void givenExistingAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributesFromView() { EntityView entityView = getEntityView(); - EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attributes\": [\"attribute1\"]}"); - when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) - .thenReturn(Futures.immediateFuture(List.of(entityView))); + mockEntityViewService(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { FutureCallback callback = invocation.getArgument(4); @@ -146,7 +135,7 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - verify(telemetryServiceMock).deleteAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); + verify(telemetryServiceMock).deleteAndNotify(eq(TENANT_ID), eq(entityView.getId()), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); } @@ -159,10 +148,7 @@ public class TbCopyAttributesToEntityViewNodeTest { TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attributes\": [\"anotherAttribute\"]}"); - when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) - .thenReturn(Futures.immediateFuture(List.of(entityView))); + mockEntityViewService(entityView); node.onMsg(ctxMock, msg); @@ -174,16 +160,12 @@ public class TbCopyAttributesToEntityViewNodeTest { @Test public void givenNonMatchedAttributesAndMsgTypeIsPostAttributesRequest_whenOnMsg_thenCopyNoAttributesToView() { EntityView entityView = getEntityView(); - EntityViewId entityViewId = entityView.getId(); TbMsg msg = TbMsg.newMsg( TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), "{\"attribute2\": \"value2\"}"); - when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) - .thenReturn(Futures.immediateFuture(List.of(entityView))); + mockEntityViewService(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { FutureCallback callback = invocation.getArgument(4); @@ -196,22 +178,19 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityViewId), eq(AttributeScope.CLIENT_SCOPE), eq(Collections.emptyList()), any(FutureCallback.class)); + verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityView.getId()), eq(AttributeScope.CLIENT_SCOPE), eq(Collections.emptyList()), any(FutureCallback.class)); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); } @Test public void givenAttributesValidityPeriodOutOfStartDateAndEndDate_whenOnMsg_thenDoNothing() { - EntityViewId entityViewId = EntityViewId.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925"); + EntityViewId entityViewId = new EntityViewId(UUID.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925")); EntityView entityView = new EntityView(entityViewId); entityView.setStartTimeMs(Instant.now().minus(2, ChronoUnit.DAYS).toEpochMilli()); entityView.setEndTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); - when(ctxMock.getTenantId()).thenReturn(TENANT_ID); - when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) - .thenReturn(Futures.immediateFuture(List.of(entityView))); + mockEntityViewService(entityView); TbMsg msg = TbMsg.newMsg( ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), @@ -230,10 +209,9 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); - ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctxMock).tellFailure(eq(msg), captor.capture()); - Throwable throwable = captor.getValue(); - assertThat(throwable).isInstanceOf(IllegalArgumentException.class).hasMessage("Message metadata is empty"); + ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); + verify(ctxMock).tellFailure(eq(msg), throwableCaptor.capture()); + assertThat(throwableCaptor.getValue()).isInstanceOf(IllegalArgumentException.class).hasMessage("Message metadata is empty"); } @ParameterizedTest @@ -249,19 +227,25 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); - ArgumentCaptor captor = ArgumentCaptor.forClass(Throwable.class); - verify(ctxMock).tellFailure(eq(msg), captor.capture()); - Throwable throwable = captor.getValue(); - assertThat(throwable).isInstanceOf(IllegalArgumentException.class).hasMessage("Unsupported msg type [" + msgType + "]"); + ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); + verify(ctxMock).tellFailure(eq(msg), throwableCaptor.capture()); + assertThat(throwableCaptor.getValue()).isInstanceOf(IllegalArgumentException.class).hasMessage("Unsupported msg type [" + msgType + "]"); } private EntityView getEntityView() { - EntityViewId entityViewId = EntityViewId.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8"); + EntityViewId entityViewId = new EntityViewId(UUID.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8")); EntityView entityView = new EntityView(entityViewId); - entityView.setStartTimeMs(FROM_DATE); - entityView.setEndTimeMs(TO_DATE); + entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); + entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); return entityView; } + + private void mockEntityViewService(EntityView entityView) { + when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any())) + .thenReturn(Futures.immediateFuture(List.of(entityView))); + } } From 4e7170090f8549b9fe63929e747d19d0486bfa47 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Tue, 28 May 2024 17:50:09 +0300 Subject: [PATCH 6/6] refactored tests to cover more test cases --- .../TbCopyAttributesToEntityViewNodeTest.java | 138 ++++++++++-------- 1 file changed, 80 insertions(+), 58 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java index 76b5b0f446..4166c05a7a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNodeTest.java @@ -32,10 +32,12 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.AttributeScope; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.objects.AttributesEntityView; @@ -56,8 +58,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; @@ -70,6 +72,18 @@ public class TbCopyAttributesToEntityViewNodeTest { private final TenantId TENANT_ID = TenantId.fromUUID(UUID.fromString("9fdb1f05-dc66-4960-9263-ae195f1b4533")); private final DeviceId DEVICE_ID = new DeviceId(UUID.fromString("1d453dc9-9333-476a-a51f-093cf2176e59")); + private final EntityViewId ENTITY_VIEW_ID = new EntityViewId(UUID.fromString("65636806-453d-4bb4-b513-92b833970753")); + + private final AttributesEntityView CLIENT_ATTRIBUTES = new AttributesEntityView(List.of("clientAttribute1"), Collections.emptyList(), Collections.emptyList()); + private final AttributesEntityView SERVER_ATTRIBUTES = new AttributesEntityView(Collections.emptyList(), List.of("serverAttribute1"), Collections.emptyList()); + private final AttributesEntityView SHARED_ATTRIBUTES = new AttributesEntityView(Collections.emptyList(), Collections.emptyList(), List.of("sharedAttribute1")); + + private final TelemetryEntityView CLIENT_TELEMETRY_ENTITY_VIEW = new TelemetryEntityView(Collections.emptyList(), CLIENT_ATTRIBUTES); + private final TelemetryEntityView SERVER_TELEMETRY_ENTITY_VIEW = new TelemetryEntityView(Collections.emptyList(), SERVER_ATTRIBUTES); + private final TelemetryEntityView SHARED_TELEMETRY_ENTITY_VIEW = new TelemetryEntityView(Collections.emptyList(), SHARED_ATTRIBUTES); + + private final long ENTITY_VIEW_START_TS = Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(); + private final long ENTITY_VIEW_END_TS = Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli(); private TbCopyAttributesToEntityViewNode node; @@ -89,14 +103,14 @@ public class TbCopyAttributesToEntityViewNodeTest { } @Test - public void givenExistingAttributes_whenOnMsg_thenCopyAttributesToView() { - EntityView entityView = getEntityView(); + public void givenExistingClientAttributes_whenOnMsg_thenCopyAttributesToView() { + EntityView entityView = getEntityView(CLIENT_TELEMETRY_ENTITY_VIEW); - TbMsg msg = TbMsg.newMsg( - TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), - "{\"attribute1\": 100, \"attribute2\": \"value2\"}"); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, + new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), + "{\"clientAttribute1\": 100, \"clientAttribute2\": \"value2\"}"); - mockEntityViewService(entityView); + mockEntityViewLookup(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { FutureCallback callback = invocation.getArgument(4); @@ -104,25 +118,33 @@ public class TbCopyAttributesToEntityViewNodeTest { return null; }).when(telemetryServiceMock).saveAndNotify(any(), any(), any(AttributeScope.class), anyList(), any(FutureCallback.class)); TbMsg newMsg = TbMsg.newMsg(msg, msg.getQueueName(), msg.getRuleChainId(), msg.getRuleNodeId()); + // TODO: use newMsg() with any(TbMsgType.class), replace in other tests as well. doAnswer(invocation -> newMsg).when(ctxMock).newMsg(any(), any(String.class), any(), any(), any(), any()); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityView.getId()), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); + ArgumentCaptor> filteredAttributesCaptor = ArgumentCaptor.forClass(List.class); + verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(ENTITY_VIEW_ID), eq(AttributeScope.CLIENT_SCOPE), + filteredAttributesCaptor.capture(), any(FutureCallback.class)); + List filteredAttributesCaptorValue = filteredAttributesCaptor.getValue(); + assertThat(filteredAttributesCaptorValue.size()).isEqualTo(1); + assertThat(filteredAttributesCaptorValue.get(0).getKey()).isEqualTo("clientAttribute1"); + assertThat(filteredAttributesCaptorValue.get(0).getValue()).isEqualTo(100L); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); + verifyNoMoreInteractions(ctxMock, entityViewServiceMock, telemetryServiceMock); } @Test - public void givenExistingAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributesFromView() { - EntityView entityView = getEntityView(); + public void givenExistingServerAttributesAndMsgTypeAttributesDeleted_whenOnMsg_thenDeleteAttributesFromView() { + EntityView entityView = getEntityView(SERVER_TELEMETRY_ENTITY_VIEW); TbMsg msg = TbMsg.newMsg( - ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), - "{\"attributes\": [\"attribute1\"]}"); + ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), + "{\"attributes\": [\"serverAttribute1\"]}"); - mockEntityViewService(entityView); + mockEntityViewLookup(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { FutureCallback callback = invocation.getArgument(4); @@ -135,37 +157,42 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - verify(telemetryServiceMock).deleteAndNotify(eq(TENANT_ID), eq(entityView.getId()), eq(AttributeScope.CLIENT_SCOPE), anyList(), any(FutureCallback.class)); + ArgumentCaptor> filteredAttributesCaptor = ArgumentCaptor.forClass(List.class); + verify(telemetryServiceMock).deleteAndNotify(eq(TENANT_ID), eq(ENTITY_VIEW_ID), eq(AttributeScope.SERVER_SCOPE), filteredAttributesCaptor.capture(), any(FutureCallback.class)); + List filteredAttributesCaptorValue = filteredAttributesCaptor.getValue(); + assertThat(filteredAttributesCaptorValue.size()).isEqualTo(1); + assertThat(filteredAttributesCaptorValue.get(0)).isEqualTo("serverAttribute1"); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); + verifyNoMoreInteractions(ctxMock, entityViewServiceMock, telemetryServiceMock); } @Test - public void givenNonMatchedAttributesAndMsgTypeIsAttributesDeleted_whenOnMsg_thenNoAttributesDeleteFromView() { - EntityView entityView = getEntityView(); + public void givenNonMatchedSharedAttributesAndMsgTypeIsAttributesDeleted_whenOnMsg_thenNoAttributesDeleteFromView() { + EntityView entityView = getEntityView(SHARED_TELEMETRY_ENTITY_VIEW); TbMsg msg = TbMsg.newMsg( - TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), + TbMsgType.ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SHARED_SCOPE.name())), "{\"attributes\": [\"anotherAttribute\"]}"); - mockEntityViewService(entityView); + mockEntityViewLookup(entityView); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); verify(ctxMock).ack(eq(msg)); - verify(ctxMock, never()).getTelemetryService(); + verifyNoMoreInteractions(ctxMock, entityViewServiceMock); } @Test public void givenNonMatchedAttributesAndMsgTypeIsPostAttributesRequest_whenOnMsg_thenCopyNoAttributesToView() { - EntityView entityView = getEntityView(); + EntityView entityView = getEntityView(CLIENT_TELEMETRY_ENTITY_VIEW); TbMsg msg = TbMsg.newMsg( - TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), - "{\"attribute2\": \"value2\"}"); + TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), + "{\"clientAttribute2\": \"value2\"}"); - mockEntityViewService(entityView); + mockEntityViewLookup(entityView); when(ctxMock.getTelemetryService()).thenReturn(telemetryServiceMock); doAnswer(invocation -> { FutureCallback callback = invocation.getArgument(4); @@ -178,71 +205,66 @@ public class TbCopyAttributesToEntityViewNodeTest { node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); - verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(entityView.getId()), eq(AttributeScope.CLIENT_SCOPE), eq(Collections.emptyList()), any(FutureCallback.class)); + verify(telemetryServiceMock).saveAndNotify(eq(TENANT_ID), eq(ENTITY_VIEW_ID), eq(AttributeScope.CLIENT_SCOPE), eq(Collections.emptyList()), any(FutureCallback.class)); verify(ctxMock).ack(eq(msg)); verify(ctxMock).enqueueForTellNext(eq(newMsg), eq(TbNodeConnectionType.SUCCESS)); + verifyNoMoreInteractions(ctxMock, entityViewServiceMock, telemetryServiceMock); } @Test public void givenAttributesValidityPeriodOutOfStartDateAndEndDate_whenOnMsg_thenDoNothing() { - EntityViewId entityViewId = new EntityViewId(UUID.fromString("d117f1a4-24ea-4fdd-b94e-5a472e99d925")); - EntityView entityView = new EntityView(entityViewId); - entityView.setStartTimeMs(Instant.now().minus(2, ChronoUnit.DAYS).toEpochMilli()); - entityView.setEndTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - - mockEntityViewService(entityView); + EntityView entityView = getEntityView( + SERVER_TELEMETRY_ENTITY_VIEW, + Instant.now().minus(2, ChronoUnit.DAYS).toEpochMilli(), + Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli() + ); + mockEntityViewLookup(entityView); TbMsg msg = TbMsg.newMsg( - ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of("scope", AttributeScope.CLIENT_SCOPE.name())), - "{\"attributes\": [\"attribute1\"]}"); - + ATTRIBUTES_DELETED, DEVICE_ID, new TbMsgMetaData(Map.of(DataConstants.SCOPE, AttributeScope.SERVER_SCOPE.name())), + "{\"attributes\": [\"serverAttribute1\"]}"); node.onMsg(ctxMock, msg); verify(entityViewServiceMock).findEntityViewsByTenantIdAndEntityIdAsync(eq(TENANT_ID), eq(DEVICE_ID)); verify(ctxMock).ack(eq(msg)); + verifyNoMoreInteractions(ctxMock, entityViewServiceMock); } - @Test - public void givenEmptyMetadata_whenOnMsg_thenThrowsException() { - TbMsg msg = TbMsg.newMsg( - ATTRIBUTES_UPDATED, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + @ParameterizedTest + @EnumSource(TbMsgType.class) + public void givenMsgTypeAndEmptyMetadata_whenOnMsg_thenVerifyFailureMsg(TbMsgType msgType) { + TbMsg msg = TbMsg.newMsg(msgType, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); node.onMsg(ctxMock, msg); ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); verify(ctxMock).tellFailure(eq(msg), throwableCaptor.capture()); - assertThat(throwableCaptor.getValue()).isInstanceOf(IllegalArgumentException.class).hasMessage("Message metadata is empty"); - } - - @ParameterizedTest - @EnumSource(TbMsgType.class) - public void givenUnsupportedMsgType_whenOnMsg_thenTellFailure(TbMsgType msgType) { - TbMsg msg = TbMsg.newMsg( - msgType, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); if (msg.isTypeOneOf(ATTRIBUTES_UPDATED, ATTRIBUTES_DELETED, ACTIVITY_EVENT, INACTIVITY_EVENT, POST_ATTRIBUTES_REQUEST)) { + assertThat(throwableCaptor.getValue()).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Message metadata is empty"); return; } + assertThat(throwableCaptor.getValue()).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Unsupported msg type [" + msgType + "]"); - node.onMsg(ctxMock, msg); - - ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); - verify(ctxMock).tellFailure(eq(msg), throwableCaptor.capture()); - assertThat(throwableCaptor.getValue()).isInstanceOf(IllegalArgumentException.class).hasMessage("Unsupported msg type [" + msgType + "]"); + verifyNoMoreInteractions(ctxMock); } - private EntityView getEntityView() { - EntityViewId entityViewId = new EntityViewId(UUID.fromString("a2109747-d1f4-475a-baaa-55f5d4897ad8")); - EntityView entityView = new EntityView(entityViewId); - entityView.setStartTimeMs(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli()); - entityView.setEndTimeMs(Instant.now().plus(1, ChronoUnit.DAYS).toEpochMilli()); - AttributesEntityView attributes = new AttributesEntityView(List.of("attribute1"), Collections.emptyList(), Collections.emptyList()); - entityView.setKeys(new TelemetryEntityView(Collections.emptyList(), attributes)); + private EntityView getEntityView(TelemetryEntityView attributesEntityView, long startTimeMs, long endTimeMs) { + EntityView entityView = new EntityView(ENTITY_VIEW_ID); + entityView.setStartTimeMs(startTimeMs); + entityView.setEndTimeMs(endTimeMs); + entityView.setKeys(attributesEntityView); return entityView; } - private void mockEntityViewService(EntityView entityView) { + private EntityView getEntityView(TelemetryEntityView attributesEntityView) { + return getEntityView(attributesEntityView, ENTITY_VIEW_START_TS, ENTITY_VIEW_END_TS); + } + + private void mockEntityViewLookup(EntityView entityView) { when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); when(entityViewServiceMock.findEntityViewsByTenantIdAndEntityIdAsync(any(), any()))