|
|
@ -23,9 +23,9 @@ import org.junit.jupiter.api.Test; |
|
|
import org.mockito.ArgumentCaptor; |
|
|
import org.mockito.ArgumentCaptor; |
|
|
import org.springframework.test.util.ReflectionTestUtils; |
|
|
import org.springframework.test.util.ReflectionTestUtils; |
|
|
import org.thingsboard.script.api.ScriptType; |
|
|
import org.thingsboard.script.api.ScriptType; |
|
|
|
|
|
import org.thingsboard.script.api.TbScriptException; |
|
|
import org.thingsboard.server.common.data.ApiUsageState; |
|
|
import org.thingsboard.server.common.data.ApiUsageState; |
|
|
import org.thingsboard.server.common.data.id.TenantId; |
|
|
import org.thingsboard.server.common.data.id.TenantId; |
|
|
import org.thingsboard.server.common.stats.DefaultStatsFactory; |
|
|
|
|
|
import org.thingsboard.server.common.stats.StatsCounter; |
|
|
import org.thingsboard.server.common.stats.StatsCounter; |
|
|
import org.thingsboard.server.common.stats.StatsFactory; |
|
|
import org.thingsboard.server.common.stats.StatsFactory; |
|
|
import org.thingsboard.server.common.stats.TbApiUsageReportClient; |
|
|
import org.thingsboard.server.common.stats.TbApiUsageReportClient; |
|
|
@ -42,8 +42,11 @@ import java.util.List; |
|
|
import java.util.Optional; |
|
|
import java.util.Optional; |
|
|
import java.util.Set; |
|
|
import java.util.Set; |
|
|
import java.util.UUID; |
|
|
import java.util.UUID; |
|
|
|
|
|
import java.util.concurrent.ExecutionException; |
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
|
|
|
|
|
import static org.assertj.core.api.InstanceOfAssertFactories.type; |
|
|
import static org.mockito.ArgumentMatchers.any; |
|
|
import static org.mockito.ArgumentMatchers.any; |
|
|
import static org.mockito.ArgumentMatchers.argThat; |
|
|
import static org.mockito.ArgumentMatchers.argThat; |
|
|
import static org.mockito.Mockito.doAnswer; |
|
|
import static org.mockito.Mockito.doAnswer; |
|
|
@ -60,7 +63,6 @@ class RemoteJsInvokeServiceTest { |
|
|
private RemoteJsInvokeService remoteJsInvokeService; |
|
|
private RemoteJsInvokeService remoteJsInvokeService; |
|
|
private TbQueueRequestTemplate<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> jsRequestTemplate; |
|
|
private TbQueueRequestTemplate<TbProtoJsQueueMsg<RemoteJsRequest>, TbProtoQueueMsg<RemoteJsResponse>> jsRequestTemplate; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@BeforeEach |
|
|
@BeforeEach |
|
|
public void beforeEach() { |
|
|
public void beforeEach() { |
|
|
TbApiUsageStateClient apiUsageStateClient = mock(TbApiUsageStateClient.class); |
|
|
TbApiUsageStateClient apiUsageStateClient = mock(TbApiUsageStateClient.class); |
|
|
@ -74,7 +76,7 @@ class RemoteJsInvokeServiceTest { |
|
|
remoteJsInvokeService.requestTemplate = jsRequestTemplate; |
|
|
remoteJsInvokeService.requestTemplate = jsRequestTemplate; |
|
|
StatsFactory statsFactory = mock(StatsFactory.class); |
|
|
StatsFactory statsFactory = mock(StatsFactory.class); |
|
|
when(statsFactory.createStatsCounter(any(), any())).thenReturn(mock(StatsCounter.class)); |
|
|
when(statsFactory.createStatsCounter(any(), any())).thenReturn(mock(StatsCounter.class)); |
|
|
ReflectionTestUtils.setField(remoteJsInvokeService, "statsFactory",statsFactory); |
|
|
ReflectionTestUtils.setField(remoteJsInvokeService, "statsFactory", statsFactory); |
|
|
remoteJsInvokeService.init(); |
|
|
remoteJsInvokeService.init(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -84,7 +86,36 @@ class RemoteJsInvokeServiceTest { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Test |
|
|
@Test |
|
|
public void whenInvokingFunction_thenDoNotSendScriptBody() throws Exception { |
|
|
void givenUncompilableScript_whenEvaluating_thenThrowsErrorWithCompilationErrorCode() { |
|
|
|
|
|
// GIVEN
|
|
|
|
|
|
doAnswer(methodCall -> Futures.immediateFuture(new TbProtoJsQueueMsg<>(UUID.randomUUID(), RemoteJsResponse.newBuilder() |
|
|
|
|
|
.setCompileResponse(JsInvokeProtos.JsCompileResponse.newBuilder() |
|
|
|
|
|
.setSuccess(false) |
|
|
|
|
|
.setErrorCode(JsInvokeProtos.JsInvokeErrorCode.COMPILATION_ERROR) |
|
|
|
|
|
.setErrorDetails("SyntaxError: Unexpected token 'const'") |
|
|
|
|
|
.setScriptHash(methodCall.<TbProtoQueueMsg<RemoteJsRequest>>getArgument(0).getValue().getCompileRequest().getScriptHash()) |
|
|
|
|
|
.build()) |
|
|
|
|
|
.build()))) |
|
|
|
|
|
.when(jsRequestTemplate).send(argThat(jsQueueMsg -> jsQueueMsg.getValue().hasCompileRequest())); |
|
|
|
|
|
|
|
|
|
|
|
var uncompilableScript = "let const = 'this is not allowed';"; |
|
|
|
|
|
|
|
|
|
|
|
// WHEN-THEN
|
|
|
|
|
|
assertThatThrownBy(() -> remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, uncompilableScript).get()) |
|
|
|
|
|
.isInstanceOf(ExecutionException.class) |
|
|
|
|
|
.cause() |
|
|
|
|
|
.isInstanceOf(TbScriptException.class) |
|
|
|
|
|
.asInstanceOf(type(TbScriptException.class)) |
|
|
|
|
|
.satisfies(ex -> { |
|
|
|
|
|
assertThat(ex.getScriptId()).isNotNull(); |
|
|
|
|
|
assertThat(ex.getErrorCode()).isEqualTo(TbScriptException.ErrorCode.COMPILATION); |
|
|
|
|
|
assertThat(ex.getBody()).contains(uncompilableScript); |
|
|
|
|
|
assertThat(ex.getCause()).isInstanceOf(RuntimeException.class).hasMessage("SyntaxError: Unexpected token 'const'"); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
void whenInvokingFunction_thenDoNotSendScriptBody() throws Exception { |
|
|
mockJsEvalResponse(); |
|
|
mockJsEvalResponse(); |
|
|
String scriptBody = "return { a: 'b'};"; |
|
|
String scriptBody = "return { a: 'b'};"; |
|
|
UUID scriptId = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, scriptBody).get(); |
|
|
UUID scriptId = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, scriptBody).get(); |
|
|
@ -110,7 +141,7 @@ class RemoteJsInvokeServiceTest { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Test |
|
|
@Test |
|
|
public void whenInvokingFunctionAndRemoteJsExecutorRemovedScript_thenHandleNotFoundErrorAndMakeInvokeRequestWithScriptBody() throws Exception { |
|
|
void whenInvokingFunctionAndRemoteJsExecutorRemovedScript_thenHandleNotFoundErrorAndMakeInvokeRequestWithScriptBody() throws Exception { |
|
|
mockJsEvalResponse(); |
|
|
mockJsEvalResponse(); |
|
|
String scriptBody = "return { a: 'b'};"; |
|
|
String scriptBody = "return { a: 'b'};"; |
|
|
UUID scriptId = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, scriptBody).get(); |
|
|
UUID scriptId = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, scriptBody).get(); |
|
|
@ -156,7 +187,7 @@ class RemoteJsInvokeServiceTest { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Test |
|
|
@Test |
|
|
public void whenDoingEval_thenSaveScriptByHashOfTenantIdAndScriptBody() throws Exception { |
|
|
void whenDoingEval_thenSaveScriptByHashOfTenantIdAndScriptBody() throws Exception { |
|
|
mockJsEvalResponse(); |
|
|
mockJsEvalResponse(); |
|
|
|
|
|
|
|
|
TenantId tenantId1 = TenantId.fromUUID(UUID.randomUUID()); |
|
|
TenantId tenantId1 = TenantId.fromUUID(UUID.randomUUID()); |
|
|
@ -187,7 +218,7 @@ class RemoteJsInvokeServiceTest { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Test |
|
|
@Test |
|
|
public void whenReleasingScript_thenCheckForHashUsages() throws Exception { |
|
|
void whenReleasingScript_thenCheckForHashUsages() throws Exception { |
|
|
mockJsEvalResponse(); |
|
|
mockJsEvalResponse(); |
|
|
String scriptBody = "return { a: 'b'};"; |
|
|
String scriptBody = "return { a: 'b'};"; |
|
|
UUID scriptId1 = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, scriptBody).get(); |
|
|
UUID scriptId1 = remoteJsInvokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, scriptBody).get(); |
|
|
|