|
|
|
@ -25,6 +25,7 @@ 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.RuleEngineDeviceRpcRequest; |
|
|
|
import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse; |
|
|
|
import org.thingsboard.rule.engine.api.RuleEngineRpcService; |
|
|
|
import org.thingsboard.rule.engine.api.TbContext; |
|
|
|
@ -54,10 +55,12 @@ import static org.mockito.Mockito.when; |
|
|
|
|
|
|
|
@ExtendWith(MockitoExtension.class) |
|
|
|
public class TbSendRPCRequestNodeTest { |
|
|
|
|
|
|
|
private final TenantId TENANT_ID = TenantId.fromUUID(UUID.fromString("d3a47f8b-d863-4c1f-b6f0-2c946b43f21c")); |
|
|
|
private final DeviceId DEVICE_ID = new DeviceId(UUID.fromString("b052ae59-b9b4-47e8-ac71-39e7124bbd66")); |
|
|
|
|
|
|
|
private TbSendRPCRequestNode node; |
|
|
|
private TbSendRpcRequestNodeConfiguration config; |
|
|
|
|
|
|
|
|
|
|
|
@Mock |
|
|
|
private TbContext ctxMock; |
|
|
|
@Mock |
|
|
|
@ -66,50 +69,28 @@ public class TbSendRPCRequestNodeTest { |
|
|
|
@BeforeEach |
|
|
|
public void setUp() throws TbNodeException { |
|
|
|
node = new TbSendRPCRequestNode(); |
|
|
|
config = new TbSendRpcRequestNodeConfiguration().defaultConfiguration(); |
|
|
|
var config = new TbSendRpcRequestNodeConfiguration().defaultConfiguration(); |
|
|
|
var configuration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); |
|
|
|
node.init(ctxMock, configuration); |
|
|
|
} |
|
|
|
|
|
|
|
@Test |
|
|
|
public void givenRpcResponseWithoutError_whenOnMsg_thenSendsRpcRequest() { |
|
|
|
DeviceId deviceId = new DeviceId(UUID.fromString("dda00a40-9d9c-4464-a759-488b9617319c")); |
|
|
|
TenantId tenantId = new TenantId(UUID.fromString("81622599-afb3-4b52-9b47-f930f11ee963")); |
|
|
|
String data = """ |
|
|
|
{ |
|
|
|
"method": "setGpio", |
|
|
|
"params": { |
|
|
|
"pin": "23", |
|
|
|
"value": 1 |
|
|
|
} |
|
|
|
} |
|
|
|
"""; |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, deviceId, TbMsgMetaData.EMPTY, data); |
|
|
|
TbMsg outMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); |
|
|
|
TbMsg outMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); |
|
|
|
|
|
|
|
when(ctxMock.getRpcService()).thenReturn(rpcServiceMock); |
|
|
|
when(ctxMock.getTenantId()).thenReturn(tenantId); |
|
|
|
when(ctxMock.getTenantId()).thenReturn(TENANT_ID); |
|
|
|
// TODO: replace deprecated method newMsg()
|
|
|
|
when(ctxMock.newMsg(any(), any(String.class), any(), any(), any(), any())).thenReturn(outMsg); |
|
|
|
|
|
|
|
doAnswer(invocation -> { |
|
|
|
Consumer<RuleEngineDeviceRpcResponse> callback = invocation.getArgument(1); |
|
|
|
Consumer<RuleEngineDeviceRpcResponse> consumer = invocation.getArgument(1); |
|
|
|
RuleEngineDeviceRpcResponse rpcResponseMock = mock(RuleEngineDeviceRpcResponse.class); |
|
|
|
when(rpcResponseMock.getError()).thenReturn(Optional.empty()); |
|
|
|
when(rpcResponseMock.getResponse()).thenReturn(Optional.of(TbMsg.EMPTY_JSON_OBJECT)); |
|
|
|
callback.accept(rpcResponseMock); |
|
|
|
consumer.accept(rpcResponseMock); |
|
|
|
return null; |
|
|
|
}).when(rpcServiceMock).sendRpcRequestToDevice(any(), any()); |
|
|
|
|
|
|
|
node.onMsg(ctxMock, msg); |
|
|
|
}).when(rpcServiceMock).sendRpcRequestToDevice(any(RuleEngineDeviceRpcRequest.class), any(Consumer.class)); |
|
|
|
|
|
|
|
verify(ctxMock).enqueueForTellNext(eq(outMsg), eq(TbNodeConnectionType.SUCCESS)); |
|
|
|
verify(ctxMock).ack(eq(msg)); |
|
|
|
} |
|
|
|
|
|
|
|
@Test |
|
|
|
public void givenRpcResponseWithError_whenOnMsg_thenTellFailure() { |
|
|
|
DeviceId deviceId = new DeviceId(UUID.fromString("dda00a40-9d9c-4464-a759-488b9617319c")); |
|
|
|
TenantId tenantId = new TenantId(UUID.fromString("81622599-afb3-4b52-9b47-f930f11ee963")); |
|
|
|
String data = """ |
|
|
|
{ |
|
|
|
"method": "setGpio", |
|
|
|
@ -119,24 +100,42 @@ public class TbSendRPCRequestNodeTest { |
|
|
|
} |
|
|
|
} |
|
|
|
"""; |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, deviceId, TbMsgMetaData.EMPTY, data); |
|
|
|
TbMsg outMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, data); |
|
|
|
node.onMsg(ctxMock, msg); |
|
|
|
|
|
|
|
verify(ctxMock).enqueueForTellNext(eq(outMsg), eq(TbNodeConnectionType.SUCCESS)); |
|
|
|
verify(ctxMock).ack(eq(msg)); |
|
|
|
} |
|
|
|
|
|
|
|
@Test |
|
|
|
public void givenRpcResponseWithError_whenOnMsg_thenTellFailure() { |
|
|
|
TbMsg outMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); |
|
|
|
|
|
|
|
when(ctxMock.getRpcService()).thenReturn(rpcServiceMock); |
|
|
|
when(ctxMock.getTenantId()).thenReturn(tenantId); |
|
|
|
when(ctxMock.getTenantId()).thenReturn(TENANT_ID); |
|
|
|
// TODO: replace deprecated method newMsg()
|
|
|
|
when(ctxMock.newMsg(any(), any(String.class), any(), any(), any(), any())).thenReturn(outMsg); |
|
|
|
|
|
|
|
doAnswer(invocation -> { |
|
|
|
Consumer<RuleEngineDeviceRpcResponse> callback = invocation.getArgument(1); |
|
|
|
Consumer<RuleEngineDeviceRpcResponse> consumer = invocation.getArgument(1); |
|
|
|
RuleEngineDeviceRpcResponse rpcResponseMock = mock(RuleEngineDeviceRpcResponse.class); |
|
|
|
when(rpcResponseMock.getError()).thenReturn(Optional.of(RpcError.NO_ACTIVE_CONNECTION)); |
|
|
|
callback.accept(rpcResponseMock); |
|
|
|
consumer.accept(rpcResponseMock); |
|
|
|
return null; |
|
|
|
}).when(rpcServiceMock).sendRpcRequestToDevice(any(), any()); |
|
|
|
}).when(rpcServiceMock).sendRpcRequestToDevice(any(RuleEngineDeviceRpcRequest.class), any(Consumer.class)); |
|
|
|
|
|
|
|
String data = """ |
|
|
|
{ |
|
|
|
"method": "setGpio", |
|
|
|
"params": { |
|
|
|
"pin": "23", |
|
|
|
"value": 1 |
|
|
|
} |
|
|
|
} |
|
|
|
"""; |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, DEVICE_ID, TbMsgMetaData.EMPTY, data); |
|
|
|
node.onMsg(ctxMock, msg); |
|
|
|
|
|
|
|
verify(ctxMock).enqueueForTellFailure(eq(outMsg), eq("NO_ACTIVE_CONNECTION")); |
|
|
|
verify(ctxMock).enqueueForTellFailure(eq(outMsg), eq(RpcError.NO_ACTIVE_CONNECTION.name())); |
|
|
|
verify(ctxMock).ack(eq(msg)); |
|
|
|
} |
|
|
|
|
|
|
|
@ -155,30 +154,26 @@ public class TbSendRPCRequestNodeTest { |
|
|
|
return entityType; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); |
|
|
|
|
|
|
|
node.onMsg(ctxMock, msg); |
|
|
|
|
|
|
|
ArgumentCaptor<Throwable> captor = ArgumentCaptor.forClass(Throwable.class); |
|
|
|
verify(ctxMock).tellFailure(eq(msg), captor.capture()); |
|
|
|
Throwable value = captor.getValue(); |
|
|
|
assertThat(value.getClass()).isEqualTo(RuntimeException.class); |
|
|
|
assertThat(value.getMessage()).isEqualTo("Message originator is not a device entity!"); |
|
|
|
ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class); |
|
|
|
verify(ctxMock).tellFailure(eq(msg), throwableCaptor.capture()); |
|
|
|
assertThat(throwableCaptor.getValue()).isInstanceOf(RuntimeException.class) |
|
|
|
.hasMessage("Message originator is not a device entity!"); |
|
|
|
} |
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
@ValueSource(strings = {"method", "params"}) |
|
|
|
public void givenMethodOrParamsAreNotPresent_whenOnMsg_thenThrowsException(String key) { |
|
|
|
DeviceId deviceId = new DeviceId(UUID.randomUUID()); |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, "{\"" + key + "\": \"value\"}"); |
|
|
|
TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, "{\"" + key + "\": \"value\"}"); |
|
|
|
|
|
|
|
node.onMsg(ctxMock, msg); |
|
|
|
|
|
|
|
ArgumentCaptor<Throwable> captor = ArgumentCaptor.forClass(Throwable.class); |
|
|
|
verify(ctxMock).tellFailure(eq(msg), captor.capture()); |
|
|
|
Throwable value = captor.getValue(); |
|
|
|
assertThat(value.getClass()).isEqualTo(RuntimeException.class); |
|
|
|
assertThat(value.getMessage()).isEqualTo( |
|
|
|
key.equals("method") ? "Params are not present in the message!" : "Method is not present in the message!"); |
|
|
|
ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class); |
|
|
|
verify(ctxMock).tellFailure(eq(msg), throwableCaptor.capture()); |
|
|
|
assertThat(throwableCaptor.getValue()).isInstanceOf(RuntimeException.class) |
|
|
|
.hasMessage(key.equals("method") ? "Params are not present in the message!" : "Method is not present in the message!"); |
|
|
|
} |
|
|
|
} |
|
|
|
|