Add optimization using separate service which routes activity actions to device state service directly, when running in monolith. Refactor rule node tests
This commit is contained in:
parent
3c460d79c3
commit
eadcf916f5
@ -31,6 +31,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.MailService;
|
||||
import org.thingsboard.rule.engine.api.NotificationCenter;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceStateManager;
|
||||
import org.thingsboard.rule.engine.api.SmsService;
|
||||
import org.thingsboard.rule.engine.api.slack.SlackService;
|
||||
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
|
||||
@ -203,6 +204,10 @@ public class ActorSystemContext {
|
||||
@Getter
|
||||
private DeviceCredentialsService deviceCredentialsService;
|
||||
|
||||
@Autowired
|
||||
@Getter
|
||||
private RuleEngineDeviceStateManager deviceStateManager;
|
||||
|
||||
@Autowired
|
||||
@Getter
|
||||
private TbTenantProfileCache tenantProfileCache;
|
||||
|
||||
@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.RuleEngineAlarmService;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineApiUsageStateService;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineAssetProfileCache;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceStateManager;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineRpcService;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
|
||||
import org.thingsboard.rule.engine.api.ScriptEngine;
|
||||
@ -683,6 +684,11 @@ class DefaultTbContext implements TbContext {
|
||||
return mainCtx.getDeviceCredentialsService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleEngineDeviceStateManager getDeviceStateManager() {
|
||||
return mainCtx.getDeviceStateManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TbClusterService getClusterService() {
|
||||
return mainCtx.getClusterService();
|
||||
|
||||
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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.server.service.state;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceStateManager;
|
||||
import org.thingsboard.server.cluster.TbClusterService;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.queue.common.SimpleTbQueueCallback;
|
||||
import org.thingsboard.server.queue.util.TbRuleEngineComponent;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@TbRuleEngineComponent
|
||||
@RequiredArgsConstructor
|
||||
public class ClusteredRuleEngineDeviceStateManager implements RuleEngineDeviceStateManager {
|
||||
|
||||
private final TbClusterService clusterService;
|
||||
|
||||
@Override
|
||||
public void onDeviceConnect(TenantId tenantId, DeviceId deviceId, long connectTime, TbCallback callback) {
|
||||
var tenantUuid = tenantId.getId();
|
||||
var deviceUuid = deviceId.getId();
|
||||
var deviceConnectMsg = TransportProtos.DeviceConnectProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastConnectTime(connectTime)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceConnectMsg(deviceConnectMsg)
|
||||
.build();
|
||||
log.trace("[{}][{}] Sending device connect message to core. Connect time: [{}].", tenantUuid, deviceUuid, connectTime);
|
||||
clusterService.pushMsgToCore(tenantId, deviceId, toCoreMsg, new SimpleTbQueueCallback(__ -> callback.onSuccess(), callback::onFailure));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceActivity(TenantId tenantId, DeviceId deviceId, long activityTime, TbCallback callback) {
|
||||
var tenantUuid = tenantId.getId();
|
||||
var deviceUuid = deviceId.getId();
|
||||
var deviceActivityMsg = TransportProtos.DeviceActivityProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastActivityTime(activityTime)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceActivityMsg(deviceActivityMsg)
|
||||
.build();
|
||||
log.trace("[{}][{}] Sending device activity message to core. Activity time: [{}].", tenantUuid, deviceUuid, activityTime);
|
||||
clusterService.pushMsgToCore(tenantId, deviceId, toCoreMsg, new SimpleTbQueueCallback(__ -> callback.onSuccess(), callback::onFailure));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDisconnect(TenantId tenantId, DeviceId deviceId, long disconnectTime, TbCallback callback) {
|
||||
var tenantUuid = tenantId.getId();
|
||||
var deviceUuid = deviceId.getId();
|
||||
var deviceDisconnectMsg = TransportProtos.DeviceDisconnectProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastDisconnectTime(disconnectTime)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceDisconnectMsg(deviceDisconnectMsg)
|
||||
.build();
|
||||
log.trace("[{}][{}] Sending device disconnect message to core. Disconnect time: [{}].", tenantUuid, deviceUuid, disconnectTime);
|
||||
clusterService.pushMsgToCore(tenantId, deviceId, toCoreMsg, new SimpleTbQueueCallback(__ -> callback.onSuccess(), callback::onFailure));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceInactivity(TenantId tenantId, DeviceId deviceId, long inactivityTime, TbCallback callback) {
|
||||
var tenantUuid = tenantId.getId();
|
||||
var deviceUuid = deviceId.getId();
|
||||
var deviceInactivityMsg = TransportProtos.DeviceInactivityProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastInactivityTime(inactivityTime)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceInactivityMsg(deviceInactivityMsg)
|
||||
.build();
|
||||
log.trace("[{}][{}] Sending device inactivity message to core. Inactivity time: [{}].", tenantUuid, deviceUuid, inactivityTime);
|
||||
clusterService.pushMsgToCore(tenantId, deviceId, toCoreMsg, new SimpleTbQueueCallback(__ -> callback.onSuccess(), callback::onFailure));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.server.service.state;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceStateManager;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Primary
|
||||
@TbCoreComponent
|
||||
@RequiredArgsConstructor
|
||||
public class LocalRuleEngineDeviceStateManager implements RuleEngineDeviceStateManager {
|
||||
|
||||
private final DeviceStateService deviceStateService;
|
||||
|
||||
@Override
|
||||
public void onDeviceConnect(TenantId tenantId, DeviceId deviceId, long connectTime, TbCallback callback) {
|
||||
try {
|
||||
deviceStateService.onDeviceConnect(tenantId, deviceId, connectTime);
|
||||
} catch (Exception e) {
|
||||
log.error("[{}][{}] Failed to process device connect event. Connect time: [{}].", tenantId.getId(), deviceId.getId(), connectTime, e);
|
||||
callback.onFailure(e);
|
||||
return;
|
||||
}
|
||||
callback.onSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceActivity(TenantId tenantId, DeviceId deviceId, long activityTime, TbCallback callback) {
|
||||
try {
|
||||
deviceStateService.onDeviceActivity(tenantId, deviceId, activityTime);
|
||||
} catch (Exception e) {
|
||||
log.error("[{}][{}] Failed to process device activity event. Activity time: [{}].", tenantId.getId(), deviceId.getId(), activityTime, e);
|
||||
callback.onFailure(e);
|
||||
return;
|
||||
}
|
||||
callback.onSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDisconnect(TenantId tenantId, DeviceId deviceId, long disconnectTime, TbCallback callback) {
|
||||
try {
|
||||
deviceStateService.onDeviceDisconnect(tenantId, deviceId, disconnectTime);
|
||||
} catch (Exception e) {
|
||||
log.error("[{}][{}] Failed to process device disconnect event. Disconnect time: [{}].", tenantId.getId(), deviceId.getId(), disconnectTime, e);
|
||||
callback.onFailure(e);
|
||||
return;
|
||||
}
|
||||
callback.onSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceInactivity(TenantId tenantId, DeviceId deviceId, long inactivityTime, TbCallback callback) {
|
||||
try {
|
||||
deviceStateService.onDeviceInactivity(tenantId, deviceId, inactivityTime);
|
||||
} catch (Exception e) {
|
||||
log.error("[{}][{}] Failed to process device inactivity event. Inactivity time: [{}].", tenantId.getId(), deviceId.getId(), inactivityTime, e);
|
||||
callback.onFailure(e);
|
||||
return;
|
||||
}
|
||||
callback.onSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 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.server.service.state;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.thingsboard.server.cluster.TbClusterService;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.queue.TbQueueCallback;
|
||||
import org.thingsboard.server.queue.TbQueueMsgMetadata;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class ClusteredRuleEngineDeviceStateManagerTest {
|
||||
|
||||
@Mock
|
||||
private static TbClusterService tbClusterServiceMock;
|
||||
@Mock
|
||||
private static TbCallback tbCallbackMock;
|
||||
@Mock
|
||||
private static TbQueueMsgMetadata metadataMock;
|
||||
@Captor
|
||||
private static ArgumentCaptor<TbQueueCallback> queueCallbackCaptor;
|
||||
private static ClusteredRuleEngineDeviceStateManager deviceStateManager;
|
||||
|
||||
private static final TenantId TENANT_ID = TenantId.fromUUID(UUID.fromString("57ab2e6c-bc4c-11ee-a506-0242ac120002"));
|
||||
private static final DeviceId DEVICE_ID = DeviceId.fromString("74a9053e-bc4c-11ee-a506-0242ac120002");
|
||||
private static final long EVENT_TS = System.currentTimeMillis();
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
deviceStateManager = new ClusteredRuleEngineDeviceStateManager(tbClusterServiceMock);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void givenProcessingSuccess_whenOnDeviceAction_thenCallsDeviceStateServiceAndOnSuccessCallback(Runnable onDeviceAction, Runnable actionVerification) {
|
||||
// WHEN
|
||||
onDeviceAction.run();
|
||||
|
||||
// THEN
|
||||
actionVerification.run();
|
||||
|
||||
TbQueueCallback callback = queueCallbackCaptor.getValue();
|
||||
callback.onSuccess(metadataMock);
|
||||
then(tbCallbackMock).should().onSuccess();
|
||||
|
||||
var runtimeException = new RuntimeException("Something bad happened!");
|
||||
callback.onFailure(runtimeException);
|
||||
then(tbCallbackMock).should().onFailure(runtimeException);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> givenProcessingSuccess_whenOnDeviceAction_thenCallsDeviceStateServiceAndOnSuccessCallback() {
|
||||
return Stream.of(
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceConnect(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> {
|
||||
var deviceConnectMsg = TransportProtos.DeviceConnectProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastConnectTime(EVENT_TS)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceConnectMsg(deviceConnectMsg)
|
||||
.build();
|
||||
then(tbClusterServiceMock).should().pushMsgToCore(eq(TENANT_ID), eq(DEVICE_ID), eq(toCoreMsg), queueCallbackCaptor.capture());
|
||||
}
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceActivity(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> {
|
||||
var deviceActivityMsg = TransportProtos.DeviceActivityProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastActivityTime(EVENT_TS)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceActivityMsg(deviceActivityMsg)
|
||||
.build();
|
||||
then(tbClusterServiceMock).should().pushMsgToCore(eq(TENANT_ID), eq(DEVICE_ID), eq(toCoreMsg), queueCallbackCaptor.capture());
|
||||
}
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceDisconnect(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> {
|
||||
var deviceDisconnectMsg = TransportProtos.DeviceDisconnectProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastDisconnectTime(EVENT_TS)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceDisconnectMsg(deviceDisconnectMsg)
|
||||
.build();
|
||||
then(tbClusterServiceMock).should().pushMsgToCore(eq(TENANT_ID), eq(DEVICE_ID), eq(toCoreMsg), queueCallbackCaptor.capture());
|
||||
}
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceInactivity(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> {
|
||||
var deviceInactivityMsg = TransportProtos.DeviceInactivityProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastInactivityTime(EVENT_TS)
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceInactivityMsg(deviceInactivityMsg)
|
||||
.build();
|
||||
then(tbClusterServiceMock).should().pushMsgToCore(eq(TENANT_ID), eq(DEVICE_ID), eq(toCoreMsg), queueCallbackCaptor.capture());
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* 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.server.service.state;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class LocalRuleEngineDeviceStateManagerTest {
|
||||
|
||||
@Mock
|
||||
private static DeviceStateService deviceStateServiceMock;
|
||||
@Mock
|
||||
private static TbCallback tbCallbackMock;
|
||||
private static LocalRuleEngineDeviceStateManager deviceStateManager;
|
||||
|
||||
private static final TenantId TENANT_ID = TenantId.fromUUID(UUID.fromString("57ab2e6c-bc4c-11ee-a506-0242ac120002"));
|
||||
private static final DeviceId DEVICE_ID = DeviceId.fromString("74a9053e-bc4c-11ee-a506-0242ac120002");
|
||||
private static final long EVENT_TS = System.currentTimeMillis();
|
||||
private static final RuntimeException RUNTIME_EXCEPTION = new RuntimeException("Something bad happened!");
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
deviceStateManager = new LocalRuleEngineDeviceStateManager(deviceStateServiceMock);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void givenProcessingSuccess_whenOnDeviceAction_thenCallsDeviceStateServiceAndOnSuccessCallback(Runnable onDeviceAction, Runnable actionVerification) {
|
||||
// WHEN
|
||||
onDeviceAction.run();
|
||||
|
||||
// THEN
|
||||
actionVerification.run();
|
||||
then(tbCallbackMock).should().onSuccess();
|
||||
then(tbCallbackMock).should(never()).onFailure(any());
|
||||
}
|
||||
|
||||
private static Stream<Arguments> givenProcessingSuccess_whenOnDeviceAction_thenCallsDeviceStateServiceAndOnSuccessCallback() {
|
||||
return Stream.of(
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceConnect(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceConnect(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceActivity(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceActivity(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceDisconnect(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceDisconnect(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> deviceStateManager.onDeviceInactivity(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceInactivity(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void givenProcessingFailure_whenOnDeviceAction_thenCallsDeviceStateServiceAndOnFailureCallback(
|
||||
Runnable exceptionThrowSetup, Runnable onDeviceAction, Runnable actionVerification
|
||||
) {
|
||||
// GIVEN
|
||||
exceptionThrowSetup.run();
|
||||
|
||||
// WHEN
|
||||
onDeviceAction.run();
|
||||
|
||||
// THEN
|
||||
actionVerification.run();
|
||||
then(tbCallbackMock).should(never()).onSuccess();
|
||||
then(tbCallbackMock).should().onFailure(RUNTIME_EXCEPTION);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> givenProcessingFailure_whenOnDeviceAction_thenCallsDeviceStateServiceAndOnFailureCallback() {
|
||||
return Stream.of(
|
||||
Arguments.of(
|
||||
(Runnable) () -> doThrow(RUNTIME_EXCEPTION).when(deviceStateServiceMock).onDeviceConnect(TENANT_ID, DEVICE_ID, EVENT_TS),
|
||||
(Runnable) () -> deviceStateManager.onDeviceConnect(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceConnect(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> doThrow(RUNTIME_EXCEPTION).when(deviceStateServiceMock).onDeviceActivity(TENANT_ID, DEVICE_ID, EVENT_TS),
|
||||
(Runnable) () -> deviceStateManager.onDeviceActivity(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceActivity(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> doThrow(RUNTIME_EXCEPTION).when(deviceStateServiceMock).onDeviceDisconnect(TENANT_ID, DEVICE_ID, EVENT_TS),
|
||||
(Runnable) () -> deviceStateManager.onDeviceDisconnect(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceDisconnect(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
),
|
||||
Arguments.of(
|
||||
(Runnable) () -> doThrow(RUNTIME_EXCEPTION).when(deviceStateServiceMock).onDeviceInactivity(TENANT_ID, DEVICE_ID, EVENT_TS),
|
||||
(Runnable) () -> deviceStateManager.onDeviceInactivity(TENANT_ID, DEVICE_ID, EVENT_TS, tbCallbackMock),
|
||||
(Runnable) () -> then(deviceStateServiceMock).should().onDeviceInactivity(TENANT_ID, DEVICE_ID, EVENT_TS)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -335,7 +335,7 @@ public final class TbMsg implements Serializable {
|
||||
this.originator = originator;
|
||||
if (customerId == null || customerId.isNullUid()) {
|
||||
if (originator != null && originator.getEntityType() == EntityType.CUSTOMER) {
|
||||
this.customerId = (CustomerId) originator;
|
||||
this.customerId = new CustomerId(originator.getId());
|
||||
} else {
|
||||
this.customerId = null;
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.api;
|
||||
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
|
||||
public interface RuleEngineDeviceStateManager {
|
||||
|
||||
void onDeviceConnect(TenantId tenantId, DeviceId deviceId, long connectTime, TbCallback callback);
|
||||
|
||||
void onDeviceActivity(TenantId tenantId, DeviceId deviceId, long activityTime, TbCallback callback);
|
||||
|
||||
void onDeviceDisconnect(TenantId tenantId, DeviceId deviceId, long disconnectTime, TbCallback callback);
|
||||
|
||||
void onDeviceInactivity(TenantId tenantId, DeviceId deviceId, long inactivityTime, TbCallback callback);
|
||||
|
||||
}
|
||||
@ -280,6 +280,8 @@ public interface TbContext {
|
||||
|
||||
DeviceCredentialsService getDeviceCredentialsService();
|
||||
|
||||
RuleEngineDeviceStateManager getDeviceStateManager();
|
||||
|
||||
TbClusterService getClusterService();
|
||||
|
||||
DashboardService getDashboardService();
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.thingsboard.rule.engine.action;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceStateManager;
|
||||
import org.thingsboard.rule.engine.api.RuleNode;
|
||||
import org.thingsboard.rule.engine.api.TbContext;
|
||||
import org.thingsboard.rule.engine.api.TbNode;
|
||||
@ -23,12 +24,12 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
|
||||
import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
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.plugin.ComponentType;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.queue.TbQueueCallback;
|
||||
import org.thingsboard.server.queue.common.SimpleTbQueueCallback;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
@ -61,7 +62,7 @@ import java.util.Set;
|
||||
)
|
||||
public class TbDeviceStateNode implements TbNode {
|
||||
|
||||
static final Set<TbMsgType> SUPPORTED_EVENTS = EnumSet.of(
|
||||
private static final Set<TbMsgType> SUPPORTED_EVENTS = EnumSet.of(
|
||||
TbMsgType.CONNECT_EVENT, TbMsgType.ACTIVITY_EVENT, TbMsgType.DISCONNECT_EVENT, TbMsgType.INACTIVITY_EVENT
|
||||
);
|
||||
|
||||
@ -85,98 +86,41 @@ public class TbDeviceStateNode implements TbNode {
|
||||
ctx.tellSuccess(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
TenantId tenantId = ctx.getTenantId();
|
||||
DeviceId deviceId = (DeviceId) msg.getOriginator();
|
||||
RuleEngineDeviceStateManager deviceStateManager = ctx.getDeviceStateManager();
|
||||
|
||||
switch (event) {
|
||||
case CONNECT_EVENT:
|
||||
sendDeviceConnectMsg(ctx, msg);
|
||||
deviceStateManager.onDeviceConnect(tenantId, deviceId, msg.getMetaDataTs(), getMsgEnqueuedCallback(ctx, msg));
|
||||
break;
|
||||
case ACTIVITY_EVENT:
|
||||
sendDeviceActivityMsg(ctx, msg);
|
||||
deviceStateManager.onDeviceActivity(tenantId, deviceId, msg.getMetaDataTs(), getMsgEnqueuedCallback(ctx, msg));
|
||||
break;
|
||||
case DISCONNECT_EVENT:
|
||||
sendDeviceDisconnectMsg(ctx, msg);
|
||||
deviceStateManager.onDeviceDisconnect(tenantId, deviceId, msg.getMetaDataTs(), getMsgEnqueuedCallback(ctx, msg));
|
||||
break;
|
||||
case INACTIVITY_EVENT:
|
||||
sendDeviceInactivityMsg(ctx, msg);
|
||||
deviceStateManager.onDeviceInactivity(tenantId, deviceId, msg.getMetaDataTs(), getMsgEnqueuedCallback(ctx, msg));
|
||||
break;
|
||||
default:
|
||||
ctx.tellFailure(msg, new IllegalStateException("Configured event [" + event + "] is not supported!"));
|
||||
}
|
||||
}
|
||||
|
||||
private void sendDeviceConnectMsg(TbContext ctx, TbMsg msg) {
|
||||
var tenantUuid = ctx.getTenantId().getId();
|
||||
var deviceUuid = msg.getOriginator().getId();
|
||||
var deviceConnectMsg = TransportProtos.DeviceConnectProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastConnectTime(msg.getMetaDataTs())
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceConnectMsg(deviceConnectMsg)
|
||||
.build();
|
||||
ctx.getClusterService().pushMsgToCore(
|
||||
ctx.getTenantId(), msg.getOriginator(), toCoreMsg, getMsgEnqueuedCallback(ctx, msg)
|
||||
);
|
||||
}
|
||||
private TbCallback getMsgEnqueuedCallback(TbContext ctx, TbMsg msg) {
|
||||
return new TbCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
ctx.tellSuccess(msg);
|
||||
}
|
||||
|
||||
private void sendDeviceActivityMsg(TbContext ctx, TbMsg msg) {
|
||||
var tenantUuid = ctx.getTenantId().getId();
|
||||
var deviceUuid = msg.getOriginator().getId();
|
||||
var deviceActivityMsg = TransportProtos.DeviceActivityProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastActivityTime(msg.getMetaDataTs())
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceActivityMsg(deviceActivityMsg)
|
||||
.build();
|
||||
ctx.getClusterService().pushMsgToCore(
|
||||
ctx.getTenantId(), msg.getOriginator(), toCoreMsg, getMsgEnqueuedCallback(ctx, msg)
|
||||
);
|
||||
}
|
||||
|
||||
private void sendDeviceDisconnectMsg(TbContext ctx, TbMsg msg) {
|
||||
var tenantUuid = ctx.getTenantId().getId();
|
||||
var deviceUuid = msg.getOriginator().getId();
|
||||
var deviceDisconnectMsg = TransportProtos.DeviceDisconnectProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastDisconnectTime(msg.getMetaDataTs())
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceDisconnectMsg(deviceDisconnectMsg)
|
||||
.build();
|
||||
ctx.getClusterService().pushMsgToCore(
|
||||
ctx.getTenantId(), msg.getOriginator(), toCoreMsg, getMsgEnqueuedCallback(ctx, msg)
|
||||
);
|
||||
}
|
||||
|
||||
private void sendDeviceInactivityMsg(TbContext ctx, TbMsg msg) {
|
||||
var tenantUuid = ctx.getTenantId().getId();
|
||||
var deviceUuid = msg.getOriginator().getId();
|
||||
var deviceInactivityMsg = TransportProtos.DeviceInactivityProto.newBuilder()
|
||||
.setTenantIdMSB(tenantUuid.getMostSignificantBits())
|
||||
.setTenantIdLSB(tenantUuid.getLeastSignificantBits())
|
||||
.setDeviceIdMSB(deviceUuid.getMostSignificantBits())
|
||||
.setDeviceIdLSB(deviceUuid.getLeastSignificantBits())
|
||||
.setLastInactivityTime(msg.getMetaDataTs())
|
||||
.build();
|
||||
var toCoreMsg = TransportProtos.ToCoreMsg.newBuilder()
|
||||
.setDeviceInactivityMsg(deviceInactivityMsg)
|
||||
.build();
|
||||
ctx.getClusterService().pushMsgToCore(
|
||||
ctx.getTenantId(), msg.getOriginator(), toCoreMsg, getMsgEnqueuedCallback(ctx, msg)
|
||||
);
|
||||
}
|
||||
|
||||
private TbQueueCallback getMsgEnqueuedCallback(TbContext ctx, TbMsg msg) {
|
||||
return new SimpleTbQueueCallback(metadata -> ctx.tellSuccess(msg), t -> ctx.tellFailure(msg, t));
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
ctx.tellFailure(msg, t);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -20,28 +20,28 @@ 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.Arguments;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
import org.thingsboard.rule.engine.api.RuleEngineDeviceStateManager;
|
||||
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.cluster.TbClusterService;
|
||||
import org.thingsboard.server.common.data.Device;
|
||||
import org.thingsboard.server.common.data.id.AssetId;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
|
||||
import org.thingsboard.server.common.data.id.RuleNodeId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.common.data.msg.TbMsgType;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.queue.TbQueueCallback;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -51,7 +51,6 @@ import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class TbDeviceStateNodeTest {
|
||||
@ -59,7 +58,9 @@ public class TbDeviceStateNodeTest {
|
||||
@Mock
|
||||
private TbContext ctxMock;
|
||||
@Mock
|
||||
private TbClusterService tbClusterServiceMock;
|
||||
private static RuleEngineDeviceStateManager deviceStateManagerMock;
|
||||
@Captor
|
||||
private static ArgumentCaptor<TbCallback> callbackCaptor;
|
||||
private TbDeviceStateNode node;
|
||||
private TbDeviceStateNodeConfiguration config;
|
||||
|
||||
@ -94,10 +95,6 @@ public class TbDeviceStateNodeTest {
|
||||
@Test
|
||||
public void givenDefaultConfiguration_whenInvoked_thenCorrectValuesAreSet() {
|
||||
assertThat(config.getEvent()).isEqualTo(TbMsgType.ACTIVITY_EVENT);
|
||||
assertThat(TbDeviceStateNode.SUPPORTED_EVENTS).isEqualTo(Set.of(
|
||||
TbMsgType.CONNECT_EVENT, TbMsgType.ACTIVITY_EVENT,
|
||||
TbMsgType.DISCONNECT_EVENT, TbMsgType.INACTIVITY_EVENT
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -113,10 +110,14 @@ public class TbDeviceStateNodeTest {
|
||||
.matches(e -> ((TbNodeException) e).isUnrecoverable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUnsupportedEventInConfig_whenInit_thenThrowsUnrecoverableTbNodeException() {
|
||||
@ParameterizedTest
|
||||
@EnumSource(
|
||||
value = TbMsgType.class,
|
||||
names = {"CONNECT_EVENT", "ACTIVITY_EVENT", "DISCONNECT_EVENT", "INACTIVITY_EVENT"},
|
||||
mode = EnumSource.Mode.EXCLUDE
|
||||
)
|
||||
public void givenUnsupportedEventInConfig_whenInit_thenThrowsUnrecoverableTbNodeException(TbMsgType unsupportedEvent) {
|
||||
// GIVEN
|
||||
var unsupportedEvent = TbMsgType.TO_SERVER_RPC_REQUEST;
|
||||
config.setEvent(unsupportedEvent);
|
||||
var nodeConfig = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||
|
||||
@ -127,11 +128,23 @@ public class TbDeviceStateNodeTest {
|
||||
.matches(e -> ((TbNodeException) e).isUnrecoverable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNonDeviceOriginator_whenOnMsg_thenTellsSuccessAndNoActivityActionsTriggered() {
|
||||
@ParameterizedTest
|
||||
@EnumSource(value = EntityType.class, names = "DEVICE", mode = EnumSource.Mode.EXCLUDE)
|
||||
public void givenNonDeviceOriginator_whenOnMsg_thenTellsSuccessAndNoActivityActionsTriggered(EntityType unsupportedType) {
|
||||
// GIVEN
|
||||
var asset = new AssetId(UUID.randomUUID());
|
||||
var msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, asset, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT);
|
||||
var nonDeviceOriginator = new EntityId() {
|
||||
|
||||
@Override
|
||||
public UUID getId() {
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getEntityType() {
|
||||
return unsupportedType;
|
||||
}
|
||||
};
|
||||
var msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, nonDeviceOriginator, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT);
|
||||
|
||||
// WHEN
|
||||
node.onMsg(ctxMock, msg);
|
||||
@ -142,10 +155,10 @@ public class TbDeviceStateNodeTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideSupportedEventsAndExpectedMessages")
|
||||
public void givenSupportedEvent_whenOnMsg_thenCorrectMsgIsSent(TbMsgType event, TransportProtos.ToCoreMsg expectedToCoreMsg) {
|
||||
@MethodSource
|
||||
public void givenInactivityEventAndDeviceOriginator_whenOnMsg_thenOnDeviceInactivityIsCalledWithCorrectCallback(TbMsgType supportedEventType, Runnable actionVerification) {
|
||||
// GIVEN
|
||||
config.setEvent(event);
|
||||
config.setEvent(supportedEventType);
|
||||
var nodeConfig = new TbNodeConfiguration(JacksonUtil.valueToTree(config));
|
||||
try {
|
||||
node.init(ctxMock, nodeConfig);
|
||||
@ -153,65 +166,34 @@ public class TbDeviceStateNodeTest {
|
||||
fail("Node failed to initialize!", e);
|
||||
}
|
||||
given(ctxMock.getTenantId()).willReturn(TENANT_ID);
|
||||
given(ctxMock.getClusterService()).willReturn(tbClusterServiceMock);
|
||||
given(ctxMock.getDeviceStateManager()).willReturn(deviceStateManagerMock);
|
||||
|
||||
// WHEN
|
||||
node.onMsg(ctxMock, msg);
|
||||
|
||||
// THEN
|
||||
var protoCaptor = ArgumentCaptor.forClass(TransportProtos.ToCoreMsg.class);
|
||||
var callbackCaptor = ArgumentCaptor.forClass(TbQueueCallback.class);
|
||||
then(tbClusterServiceMock).should().pushMsgToCore(eq(TENANT_ID), eq(DEVICE_ID), protoCaptor.capture(), callbackCaptor.capture());
|
||||
actionVerification.run();
|
||||
|
||||
TbQueueCallback actualCallback = callbackCaptor.getValue();
|
||||
TbCallback actualCallback = callbackCaptor.getValue();
|
||||
|
||||
actualCallback.onSuccess(null);
|
||||
actualCallback.onSuccess();
|
||||
then(ctxMock).should().tellSuccess(msg);
|
||||
|
||||
var throwable = new Throwable();
|
||||
actualCallback.onFailure(throwable);
|
||||
then(ctxMock).should().tellFailure(msg, throwable);
|
||||
|
||||
assertThat(expectedToCoreMsg).isEqualTo(protoCaptor.getValue());
|
||||
|
||||
then(tbClusterServiceMock).shouldHaveNoMoreInteractions();
|
||||
then(deviceStateManagerMock).shouldHaveNoMoreInteractions();
|
||||
then(ctxMock).shouldHaveNoMoreInteractions();
|
||||
}
|
||||
|
||||
private static Stream<Arguments> provideSupportedEventsAndExpectedMessages() {
|
||||
private static Stream<Arguments> givenInactivityEventAndDeviceOriginator_whenOnMsg_thenOnDeviceInactivityIsCalledWithCorrectCallback() {
|
||||
return Stream.of(
|
||||
Arguments.of(TbMsgType.CONNECT_EVENT, TransportProtos.ToCoreMsg.newBuilder().setDeviceConnectMsg(
|
||||
TransportProtos.DeviceConnectProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastConnectTime(METADATA_TS)
|
||||
.build()).build()),
|
||||
Arguments.of(TbMsgType.ACTIVITY_EVENT, TransportProtos.ToCoreMsg.newBuilder().setDeviceActivityMsg(
|
||||
TransportProtos.DeviceActivityProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastActivityTime(METADATA_TS)
|
||||
.build()).build()),
|
||||
Arguments.of(TbMsgType.DISCONNECT_EVENT, TransportProtos.ToCoreMsg.newBuilder().setDeviceDisconnectMsg(
|
||||
TransportProtos.DeviceDisconnectProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastDisconnectTime(METADATA_TS)
|
||||
.build()).build()),
|
||||
Arguments.of(TbMsgType.INACTIVITY_EVENT, TransportProtos.ToCoreMsg.newBuilder().setDeviceInactivityMsg(
|
||||
TransportProtos.DeviceInactivityProto.newBuilder()
|
||||
.setTenantIdMSB(TENANT_ID.getId().getMostSignificantBits())
|
||||
.setTenantIdLSB(TENANT_ID.getId().getLeastSignificantBits())
|
||||
.setDeviceIdMSB(DEVICE_ID.getId().getMostSignificantBits())
|
||||
.setDeviceIdLSB(DEVICE_ID.getId().getLeastSignificantBits())
|
||||
.setLastInactivityTime(METADATA_TS)
|
||||
.build()).build())
|
||||
Arguments.of(TbMsgType.CONNECT_EVENT, (Runnable) () -> then(deviceStateManagerMock).should().onDeviceConnect(eq(TENANT_ID), eq(DEVICE_ID), eq(METADATA_TS), callbackCaptor.capture())),
|
||||
Arguments.of(TbMsgType.ACTIVITY_EVENT, (Runnable) () -> then(deviceStateManagerMock).should().onDeviceActivity(eq(TENANT_ID), eq(DEVICE_ID), eq(METADATA_TS), callbackCaptor.capture())),
|
||||
Arguments.of(TbMsgType.DISCONNECT_EVENT, (Runnable) () -> then(deviceStateManagerMock).should().onDeviceDisconnect(eq(TENANT_ID), eq(DEVICE_ID), eq(METADATA_TS), callbackCaptor.capture())),
|
||||
Arguments.of(TbMsgType.INACTIVITY_EVENT, (Runnable) () -> then(deviceStateManagerMock).should().onDeviceInactivity(eq(TENANT_ID), eq(DEVICE_ID), eq(METADATA_TS), callbackCaptor.capture()))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user