@ -18,18 +18,16 @@ package org.thingsboard.rule.engine.math;
import com.fasterxml.jackson.databind.node.ObjectNode ;
import com.google.common.util.concurrent.Futures ;
import lombok.extern.slf4j.Slf4j ;
import org.awaitility.Awaitility ;
import org.junit.Assert ;
import org.junit.jupiter.api.AfterEach ;
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.Arguments ;
import org.junit.jupiter.params.provider.MethodSource ;
import org.mockito.ArgumentCaptor ;
import org.mockito.Mock ;
import org.mockito.Mockito ;
import org.mockito.junit.jupiter.MockitoExtension ;
import org.mockito.verification.Timeout ;
import org.springframework.test.util.ReflectionTestUtils ;
import org.thingsboard.common.util.AbstractListeningExecutor ;
import org.thingsboard.common.util.JacksonUtil ;
import org.thingsboard.rule.engine.api.RuleEngineTelemetryService ;
@ -55,25 +53,31 @@ import java.util.Arrays;
import java.util.List ;
import java.util.Optional ;
import java.util.UUID ;
import java.util.concurrent.ConcurrentMap ;
import java.util.concurrent.CountDownLatch ;
import java.util.concurrent.TimeUnit ;
import java.util.stream.Collectors ;
import java.util.stream.IntStream ;
import java.util.stream.Stream ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.junit.jupiter.api.Assertions.assertEquals ;
import static org.junit.jupiter.api.Assertions.assertFalse ;
import static org.junit.jupiter.api.Assertions.assertNotNull ;
import static org.junit.jupiter.api.Assertions.assertThrows ;
import static org.junit.jupiter.api.Assertions.assertTrue ;
import static org.mockito.ArgumentMatchers.any ;
import static org.mockito.ArgumentMatchers.anyDouble ;
import static org.mockito.ArgumentMatchers.anyString ;
import static org.mockito.ArgumentMatchers.argThat ;
import static org.mockito.ArgumentMatchers.eq ;
import static org.mockito.BDDMockito.willAnswer ;
import static org.mockito.Mockito.lenient ;
import static org.mockito.BDDMockito.willReturn ;
import static org.mockito.Mockito.never ;
import static org.mockito.Mockito.spy ;
import static org.mockito.Mockito.timeout ;
import static org.mockito.Mockito.times ;
import static org.mockito.Mockito.verify ;
import static org.mockito.Mockito.when ;
@Slf4j
@ExtendWith ( MockitoExtension . class )
@ -81,10 +85,11 @@ public class TbMathNodeTest {
static final int RULE_DISPATCHER_POOL_SIZE = 2 ;
static final int DB_CALLBACK_POOL_SIZE = 3 ;
static final long TIMEOUT = TimeUnit . SECONDS . toMillis ( 5 ) ;
private final EntityId originator = DeviceId . fromString ( "ccd71696-0586-422d-940e-755a41ec3b0d" ) ;
private final TenantId tenantId = TenantId . fromUUID ( UUID . fromString ( "e7f46b23-0c7d-42f5-9b06-fc35ab17af8a" ) ) ;
@Mock
@Mock ( lenient = true )
private TbContext ctx ;
@Mock
private AttributesService attributesService ;
@ -102,11 +107,11 @@ public class TbMathNodeTest {
ruleEngineDispatcherExecutor = new RuleDispatcherExecutor ( ) ;
ruleEngineDispatcherExecutor . init ( ) ;
lenient ( ) . when ( ctx . getAttributesService ( ) ) . thenReturn ( attributesService ) ;
lenient ( ) . when ( ctx . getTelemetryService ( ) ) . thenReturn ( telemetryService ) ;
lenient ( ) . when ( ctx . getTimeseriesService ( ) ) . thenReturn ( tsService ) ;
lenient ( ) . when ( ctx . getTenantId ( ) ) . thenReturn ( tenantId ) ;
lenient ( ) . when ( ctx . getDbCallbackExecutor ( ) ) . thenReturn ( dbCallbackExecutor ) ;
willReturn ( dbCallbackExecutor ) . given ( ctx ) . getDbCallbackExecutor ( ) ;
willReturn ( attributesService ) . given ( ctx ) . getAttributesService ( ) ;
willReturn ( telemetryService ) . given ( ctx ) . getTelemetryService ( ) ;
willReturn ( tsService ) . given ( ctx ) . getTimeseriesService ( ) ;
willReturn ( tenantId ) . given ( ctx ) . getTenantId ( ) ;
}
@AfterEach
@ -115,10 +120,6 @@ public class TbMathNodeTest {
dbCallbackExecutor . executor ( ) . shutdownNow ( ) ;
}
private void initMocks ( ) {
Mockito . clearInvocations ( ctx , attributesService , tsService , telemetryService ) ;
}
private TbMathNode initNode ( TbRuleNodeMathFunctionType operation , TbMathResult result , TbMathArgument . . . arguments ) {
return initNode ( operation , null , result , arguments ) ;
}
@ -161,9 +162,6 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ConcurrentMap < EntityId , TbMathNode . SemaphoreWithQueue < TbMathNode . TbMsgTbContext > > semaphores = ( ConcurrentMap < EntityId , TbMathNode . SemaphoreWithQueue < TbMathNode . TbMsgTbContext > > ) ReflectionTestUtils . getField ( node , "locks" ) ;
Assert . assertNotNull ( semaphores ) ;
metaData . putValue ( "key1" , "secondMsgResult" ) ;
metaData . putValue ( "key2" , "argumentC" ) ;
msgNode = JacksonUtil . newObjectNode ( )
@ -172,80 +170,43 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
Awaitility . await ( "Semaphore released" ) . atMost ( 5 , TimeUnit . SECONDS ) . until ( ( ) - > semaphores . get ( originator ) . semaphore . tryAcquire ( ) ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . times ( 2 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) . times ( 2 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
List < TbMsg > resultMsgs = msgCaptor . getAllValues ( ) ;
Assert . assertFalse ( resultMsgs . isEmpty ( ) ) ;
Assert . assertEquals ( 2 , resultMsgs . size ( ) ) ;
assertFalse ( resultMsgs . isEmpty ( ) ) ;
assertEquals ( 2 , resultMsgs . size ( ) ) ;
for ( int i = 0 ; i < resultMsgs . size ( ) ; i + + ) {
TbMsg outMsg = resultMsgs . get ( i ) ;
Assert . assertNotNull ( outMsg ) ;
Assert . assertNotNull ( outMsg . getData ( ) ) ;
assertNotNull ( outMsg ) ;
assertNotNull ( outMsg . getData ( ) ) ;
var resultJson = JacksonUtil . toJsonNode ( outMsg . getData ( ) ) ;
String resultKey = i = = 0 ? "firstMsgResult" : "secondMsgResult" ;
Assert . assertTrue ( resultJson . has ( resultKey ) ) ;
Assert . assertEquals ( i = = 0 ? 10 : 17 , resultJson . get ( resultKey ) . asInt ( ) ) ;
assertTrue ( resultJson . has ( resultKey ) ) ;
assertEquals ( i = = 0 ? 10 : 17 , resultJson . get ( resultKey ) . asInt ( ) ) ;
}
semaphores . remove ( originator ) ;
}
@Test
public void testSimpleFunctions ( ) {
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . ADD , 2 . 1 , 2 . 2 , 4 . 3 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . SUB , 2 . 1 , 2 . 2 , - 0 . 1 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . MULT , 2 . 1 , 2 . 0 , 4 . 2 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . DIV , 4 . 2 , 2 . 0 , 2 . 1 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . SIN , Math . toRadians ( 30 ) , 0 . 5 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . SIN , Math . toRadians ( 90 ) , 1 . 0 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . SINH , Math . toRadians ( 0 ) , 0 . 0 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . COSH , Math . toRadians ( 0 ) , 1 . 0 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . COS , Math . toRadians ( 60 ) , 0 . 5 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . COS , Math . toRadians ( 0 ) , 1 . 0 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . TAN , Math . toRadians ( 45 ) , 1 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . TAN , Math . toRadians ( 0 ) , 0 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . TANH , 90 , 1 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . ACOS , 0 . 5 , 1 . 05 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . ASIN , 0 . 5 , 0 . 52 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . ATAN , 0 . 5 , 0 . 46 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . ATAN2 , 0 . 5 , 0 . 3 , 1 . 03 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . EXP , 1 , 2 . 72 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . EXPM1 , 1 , 1 . 72 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . ABS , - 1 , 1 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . SQRT , 4 , 2 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . CBRT , 8 , 2 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . GET_EXP , 4 , 2 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . HYPOT , 4 , 5 , 6 . 4 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . LOG , 4 , 1 . 39 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . LOG10 , 4 , 0 . 6 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . LOG1P , 4 , 1 . 61 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . CEIL , 1 . 55 , 2 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . FLOOR , 23 . 97 , 23 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . FLOOR_DIV , 5 , 3 , 1 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . FLOOR_MOD , 6 , 3 , 0 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . MIN , 5 , 3 , 3 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . MAX , 5 , 3 , 5 ) ;
testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType . POW , 5 , 3 , 125 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . SIGNUM , 0 . 55 , 1 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . RAD , 5 , 0 . 09 ) ;
testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType . DEG , 5 , 286 . 48 ) ;
private static Stream < Arguments > testSimpleTwoArgumentFunction ( ) {
return Stream . of (
Arguments . of ( TbRuleNodeMathFunctionType . ADD , 2 . 1 , 2 . 2 , 4 . 3 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . SUB , 2 . 1 , 2 . 2 , - 0 . 1 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . MULT , 2 . 1 , 2 . 0 , 4 . 2 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . DIV , 4 . 2 , 2 . 0 , 2 . 1 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . ATAN2 , 0 . 5 , 0 . 3 , 1 . 03 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . HYPOT , 4 , 5 , 6 . 4 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . FLOOR_DIV , 5 , 3 , 1 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . FLOOR_MOD , 6 , 3 , 0 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . MIN , 5 , 3 , 3 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . MAX , 5 , 3 , 5 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . POW , 5 , 3 , 125 )
) ;
}
private void testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType function , double arg1 , double arg2 , double result ) {
initMocks ( ) ;
@ParameterizedTest
@MethodSource
public void testSimpleTwoArgumentFunction ( TbRuleNodeMathFunctionType function , double arg1 , double arg2 , double result ) {
var node = initNode ( function ,
new TbMathResult ( TbMathArgumentType . MESSAGE_BODY , "result" , 2 , false , false , null ) ,
new TbMathArgument ( TbMathArgumentType . MESSAGE_BODY , "a" ) ,
@ -257,19 +218,59 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) . times ( 1 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) . times ( 1 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var resultJson = JacksonUtil . toJsonNode ( resultMsg . getData ( ) ) ;
Assert . assertTrue ( resultJson . has ( "result" ) ) ;
Assert . assertEquals ( result , resultJson . get ( "result" ) . asDouble ( ) , 0d ) ;
assertTrue ( resultJson . has ( "result" ) ) ;
assertEquals ( result , resultJson . get ( "result" ) . asDouble ( ) , 0d ) ;
}
private void testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType function , double arg1 , double result ) {
initMocks ( ) ;
private static Stream < Arguments > testSimpleOneArgumentFunction ( ) {
return Stream . of (
Arguments . of ( TbRuleNodeMathFunctionType . SIN , Math . toRadians ( 30 ) , 0 . 5 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . SIN , Math . toRadians ( 90 ) , 1 . 0 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . SINH , Math . toRadians ( 0 ) , 0 . 0 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . COSH , Math . toRadians ( 0 ) , 1 . 0 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . COS , Math . toRadians ( 60 ) , 0 . 5 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . COS , Math . toRadians ( 0 ) , 1 . 0 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . TAN , Math . toRadians ( 45 ) , 1 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . TAN , Math . toRadians ( 0 ) , 0 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . TANH , 90 , 1 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . ACOS , 0 . 5 , 1 . 05 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . ASIN , 0 . 5 , 0 . 52 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . ATAN , 0 . 5 , 0 . 46 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . EXP , 1 , 2 . 72 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . EXPM1 , 1 , 1 . 72 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . ABS , - 1 , 1 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . SQRT , 4 , 2 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . CBRT , 8 , 2 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . GET_EXP , 4 , 2 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . LOG , 4 , 1 . 39 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . LOG10 , 4 , 0 . 6 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . LOG1P , 4 , 1 . 61 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . CEIL , 1 . 55 , 2 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . FLOOR , 23 . 97 , 23 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . SIGNUM , 0 . 55 , 1 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . RAD , 5 , 0 . 09 ) ,
Arguments . of ( TbRuleNodeMathFunctionType . DEG , 5 , 286 . 48 )
) ;
}
@ParameterizedTest
@MethodSource
public void testSimpleOneArgumentFunction ( TbRuleNodeMathFunctionType function , double arg1 , double result ) {
var node = initNode ( function ,
new TbMathResult ( TbMathArgumentType . MESSAGE_BODY , "result" , 2 , false , false , null ) ,
new TbMathArgument ( TbMathArgumentType . MESSAGE_BODY , "a" )
@ -280,14 +281,14 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) . times ( 1 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var resultJson = JacksonUtil . toJsonNode ( resultMsg . getData ( ) ) ;
Assert . assertTrue ( resultJson . has ( "result" ) ) ;
Assert . assertEquals ( result , resultJson . get ( "result" ) . asDouble ( ) , 0d ) ;
assertTrue ( resultJson . has ( "result" ) ) ;
assertEquals ( result , resultJson . get ( "result" ) . asDouble ( ) , 0d ) ;
}
@Test
@ -303,14 +304,14 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var resultJson = JacksonUtil . toJsonNode ( resultMsg . getData ( ) ) ;
Assert . assertTrue ( resultJson . has ( "result" ) ) ;
Assert . assertEquals ( 4 , resultJson . get ( "result" ) . asInt ( ) ) ;
assertTrue ( resultJson . has ( "result" ) ) ;
assertEquals ( 4 , resultJson . get ( "result" ) . asInt ( ) ) ;
}
@Test
@ -326,15 +327,15 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
Assert . assertNotNull ( resultMsg . getMetaData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg . getMetaData ( ) ) ;
var result = resultMsg . getMetaData ( ) . getValue ( "result" ) ;
Assert . assertNotNull ( result ) ;
Assert . assertEquals ( "4" , result ) ;
assertNotNull ( result ) ;
assertEquals ( "4" , result ) ;
}
@Test
@ -347,23 +348,23 @@ public class TbMathNodeTest {
TbMsg msg = TbMsg . newMsg ( TbMsgType . POST_TELEMETRY_REQUEST , originator , TbMsgMetaData . EMPTY , JacksonUtil . newObjectNode ( ) . toString ( ) ) ;
Mockito . when ( attributesService . find ( tenantId , originator , DataConstants . SERVER_SCOPE , "a" ) )
when ( attributesService . find ( tenantId , originator , DataConstants . SERVER_SCOPE , "a" ) )
. thenReturn ( Futures . immediateFuture ( Optional . of ( new BaseAttributeKvEntry ( System . currentTimeMillis ( ) , new DoubleDataEntry ( "a" , 2 . 0 ) ) ) ) ) ;
Mockito . when ( tsService . findLatest ( tenantId , originator , "b" ) )
when ( tsService . findLatest ( tenantId , originator , "b" ) )
. thenReturn ( Futures . immediateFuture ( Optional . of ( new BasicTsKvEntry ( System . currentTimeMillis ( ) , new LongDataEntry ( "b" , 2L ) ) ) ) ) ;
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var resultJson = JacksonUtil . toJsonNode ( resultMsg . getData ( ) ) ;
Assert . assertTrue ( resultJson . has ( "result" ) ) ;
Assert . assertEquals ( 4 , resultJson . get ( "result" ) . asInt ( ) ) ;
assertTrue ( resultJson . has ( "result" ) ) ;
assertEquals ( 4 , resultJson . get ( "result" ) . asInt ( ) ) ;
}
@Test
@ -378,14 +379,14 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var resultJson = JacksonUtil . toJsonNode ( resultMsg . getData ( ) ) ;
Assert . assertTrue ( resultJson . has ( "result" ) ) ;
Assert . assertEquals ( 2 . 236 , resultJson . get ( "result" ) . asDouble ( ) , 0 . 0 ) ;
assertTrue ( resultJson . has ( "result" ) ) ;
assertEquals ( 2 . 236 , resultJson . get ( "result" ) . asDouble ( ) , 0 . 0 ) ;
}
@Test
@ -400,14 +401,14 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var result = resultMsg . getMetaData ( ) . getValue ( "result" ) ;
Assert . assertNotNull ( result ) ;
Assert . assertEquals ( "2.236" , result ) ;
assertNotNull ( result ) ;
assertEquals ( "2.236" , result ) ;
}
@Test
@ -419,21 +420,21 @@ public class TbMathNodeTest {
TbMsg msg = TbMsg . newMsg ( TbMsgType . POST_TELEMETRY_REQUEST , originator , TbMsgMetaData . EMPTY , JacksonUtil . newObjectNode ( ) . put ( "a" , 5 ) . toString ( ) ) ;
Mockito . when ( telemetryService . saveAttrAndNotify ( any ( ) , any ( ) , anyString ( ) , anyString ( ) , anyDouble ( ) ) )
when ( telemetryService . saveAttrAndNotify ( any ( ) , any ( ) , anyString ( ) , anyString ( ) , anyDouble ( ) ) )
. thenReturn ( Futures . immediateFuture ( null ) ) ;
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
Mockito . verify ( telemetryService , times ( 1 ) ) . saveAttrAndNotify ( any ( ) , any ( ) , anyString ( ) , anyString ( ) , anyDouble ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( telemetryService , times ( 1 ) ) . saveAttrAndNotify ( any ( ) , any ( ) , anyString ( ) , anyString ( ) , anyDouble ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var result = resultMsg . getMetaData ( ) . getValue ( "result" ) ;
Assert . assertNotNull ( result ) ;
Assert . assertEquals ( "2.236" , result ) ;
assertNotNull ( result ) ;
assertEquals ( "2.236" , result ) ;
}
@Test
@ -444,21 +445,21 @@ public class TbMathNodeTest {
) ;
TbMsg msg = TbMsg . newMsg ( TbMsgType . POST_TELEMETRY_REQUEST , originator , TbMsgMetaData . EMPTY , JacksonUtil . newObjectNode ( ) . put ( "a" , 5 ) . toString ( ) ) ;
Mockito . when ( telemetryService . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) )
when ( telemetryService . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) )
. thenReturn ( Futures . immediateFuture ( null ) ) ;
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
Mockito . verify ( telemetryService , times ( 1 ) ) . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( telemetryService , times ( 1 ) ) . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var resultJson = JacksonUtil . toJsonNode ( resultMsg . getData ( ) ) ;
Assert . assertTrue ( resultJson . has ( "result" ) ) ;
Assert . assertEquals ( 2 . 236 , resultJson . get ( "result" ) . asDouble ( ) , 0 . 0 ) ;
assertTrue ( resultJson . has ( "result" ) ) ;
assertEquals ( 2 . 236 , resultJson . get ( "result" ) . asDouble ( ) , 0 . 0 ) ;
}
@Test
@ -469,26 +470,26 @@ public class TbMathNodeTest {
) ;
TbMsg msg = TbMsg . newMsg ( TbMsgType . POST_TELEMETRY_REQUEST , originator , TbMsgMetaData . EMPTY , JacksonUtil . newObjectNode ( ) . put ( "a" , 5 ) . toString ( ) ) ;
Mockito . when ( telemetryService . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) )
when ( telemetryService . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) )
. thenReturn ( Futures . immediateFuture ( null ) ) ;
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
Mockito . verify ( telemetryService , times ( 1 ) ) . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( telemetryService , times ( 1 ) ) . saveAndNotify ( any ( ) , any ( ) , any ( TsKvEntry . class ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var resultMetadata = resultMsg . getMetaData ( ) . getValue ( "result" ) ;
var resultData = JacksonUtil . toJsonNode ( resultMsg . getData ( ) ) ;
Assert . assertTrue ( resultData . has ( "result" ) ) ;
Assert . assertEquals ( 2 . 236 , resultData . get ( "result" ) . asDouble ( ) , 0 . 0 ) ;
assertTrue ( resultData . has ( "result" ) ) ;
assertEquals ( 2 . 236 , resultData . get ( "result" ) . asDouble ( ) , 0 . 0 ) ;
Assert . assertNotNull ( resultMetadata ) ;
Assert . assertEquals ( "2.236" , resultMetadata ) ;
assertNotNull ( resultMetadata ) ;
assertEquals ( "2.236" , resultMetadata ) ;
}
@Test
@ -503,14 +504,14 @@ public class TbMathNodeTest {
node . onMsg ( ctx , msg ) ;
ArgumentCaptor < TbMsg > msgCaptor = ArgumentCaptor . forClass ( TbMsg . class ) ;
Mockito . verify ( ctx , Mockito . timeout ( 5000 ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) ) . tellSuccess ( msgCaptor . capture ( ) ) ;
TbMsg resultMsg = msgCaptor . getValue ( ) ;
Assert . assertNotNull ( resultMsg ) ;
Assert . assertNotNull ( resultMsg . getData ( ) ) ;
assertNotNull ( resultMsg ) ;
assertNotNull ( resultMsg . getData ( ) ) ;
var result = resultMsg . getMetaData ( ) . getValue ( "result" ) ;
Assert . assertNotNull ( result ) ;
Assert . assertEquals ( "2.236" , result ) ;
assertNotNull ( result ) ;
assertEquals ( "2.236" , result ) ;
}
@Test
@ -523,7 +524,7 @@ public class TbMathNodeTest {
Throwable thrown = assertThrows ( RuntimeException . class , ( ) - > {
node . onMsg ( ctx , msg ) ;
} ) ;
Assert . assertNotNull ( thrown . getMessage ( ) ) ;
assertNotNull ( thrown . getMessage ( ) ) ;
}
@Test
@ -537,7 +538,7 @@ public class TbMathNodeTest {
Throwable thrown = assertThrows ( RuntimeException . class , ( ) - > {
node . onMsg ( ctx , msg ) ;
} ) ;
Assert . assertNotNull ( thrown . getMessage ( ) ) ;
assertNotNull ( thrown . getMessage ( ) ) ;
}
@Test
@ -594,16 +595,16 @@ public class TbMathNodeTest {
// submit slow msg may block all rule engine dispatcher threads
slowMsgList . forEach ( msg - > ruleEngineDispatcherExecutor . executeAsync ( ( ) - > node . onMsg ( ctx , msg ) ) ) ;
// wait until dispatcher threads started with all slowMsg
verify ( node , new Timeout ( TimeUnit . SECONDS . toMillis ( 5 ) , times ( slowMsgList . size ( ) ) ) ) . onMsg ( eq ( ctx ) , argThat ( slowMsgList : : contains ) ) ;
verify ( node , timeout ( TIMEOUT ) . times ( slowMsgList . size ( ) ) ) . onMsg ( eq ( ctx ) , argThat ( slowMsgList : : contains ) ) ;
// submit fast have to return immediately
fastMsgList . forEach ( msg - > ruleEngineDispatcherExecutor . executeAsync ( ( ) - > node . onMsg ( ctx , msg ) ) ) ;
// wait until all fast messages processed
verify ( ctx , new Timeout ( TimeUnit . SECONDS . toMillis ( 5 ) , times ( fastMsgList . size ( ) ) ) ) . tellSuccess ( any ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) . times ( fastMsgList . size ( ) ) ) . tellSuccess ( any ( ) ) ;
slowProcessingLatch . countDown ( ) ;
verify ( ctx , new Timeout ( TimeUnit . SECONDS . toMillis ( 5 ) , times ( fastMsgList . size ( ) + slowMsgList . size ( ) ) ) ) . tellSuccess ( any ( ) ) ;
verify ( ctx , timeout ( TIMEOUT ) . times ( fastMsgList . size ( ) + slowMsgList . size ( ) ) ) . tellSuccess ( any ( ) ) ;
verify ( ctx , never ( ) ) . tellFailure ( any ( ) , any ( ) ) ;
}