Test script controller and test fixes

This commit is contained in:
Andrii Shvaika 2022-10-19 16:26:26 +03:00
parent d3f06bd3a4
commit 42832aab8c
6 changed files with 63 additions and 28 deletions

View File

@ -38,6 +38,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.api.ScriptEngine;
import org.thingsboard.script.api.js.JsInvokeService;
import org.thingsboard.script.api.mvel.MvelInvokeService;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
import org.thingsboard.server.common.data.EventInfo;
@ -60,6 +61,7 @@ import org.thingsboard.server.common.data.rule.RuleChainImportResult;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.script.ScriptLanguage;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -67,6 +69,7 @@ import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.rule.TbRuleChainService;
import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
import org.thingsboard.server.service.script.RuleNodeMvelScriptEngine;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@ -117,10 +120,10 @@ public class RuleChainController extends BaseController {
private static final String RULE_CHAIN_DESCRIPTION = "The rule chain object is lightweight and contains general information about the rule chain. " +
"List of rule nodes and their connection is stored in a separate 'metadata' object.";
private static final String RULE_CHAIN_METADATA_DESCRIPTION = "The metadata object contains information about the rule nodes and their connections.";
private static final String TEST_JS_FUNCTION = "Execute the JavaScript function and return the result. The format of request: \n\n"
private static final String TEST_SCRIPT_FUNCTION = "Execute the Script function and return the result. The format of request: \n\n"
+ MARKDOWN_CODE_BLOCK_START
+ "{\n" +
" \"script\": \"Your JS Function as String\",\n" +
" \"script\": \"Your Function as String\",\n" +
" \"scriptType\": \"One of: update, generate, filter, switch, json, string\",\n" +
" \"argNames\": [\"msg\", \"metadata\", \"type\"],\n" +
" \"msg\": \"{\\\"temperature\\\": 42}\", \n" +
@ -140,7 +143,10 @@ public class RuleChainController extends BaseController {
private EventService eventService;
@Autowired
private JsInvokeService scriptInvokeService;
private JsInvokeService jsInvokeService;
@Autowired(required = false)
private MvelInvokeService mvelInvokeService;
@Autowired(required = false)
private ActorSystemContext actorContext;
@ -148,6 +154,9 @@ public class RuleChainController extends BaseController {
@Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}")
private boolean debugPerTenantEnabled;
@Value("${mvel.enabled:true}")
private boolean mvelEnabled;
@ApiOperation(value = "Get Rule Chain (getRuleChainById)",
notes = "Fetch the Rule Chain object based on the provided Rule Chain Id. " + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@ -369,13 +378,23 @@ public class RuleChainController extends BaseController {
}
}
@ApiOperation(value = "Is MVEL script executor enabled",
notes = "Returns 'True' if the MVEL script execution is enabled" + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/mvelEnabled", method = RequestMethod.GET)
@ResponseBody
public Boolean isMvelEnabled() {
return mvelEnabled;
}
@ApiOperation(value = "Test JavaScript function",
notes = TEST_JS_FUNCTION + TENANT_AUTHORITY_PARAGRAPH)
@ApiOperation(value = "Test Script function",
notes = TEST_SCRIPT_FUNCTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/testScript", method = RequestMethod.POST)
@ResponseBody
public JsonNode testScript(
@ApiParam(value = "Script language: JS or MVEL")
@RequestParam(required = false) ScriptLanguage scriptLang,
@ApiParam(value = "Test JS request. See API call description above.")
@RequestBody JsonNode inputParams) throws ThingsboardException {
try {
@ -393,7 +412,17 @@ public class RuleChainController extends BaseController {
String errorText = "";
ScriptEngine engine = null;
try {
engine = new RuleNodeJsScriptEngine(getTenantId(), scriptInvokeService, script, argNames);
if (scriptLang == null) {
scriptLang = ScriptLanguage.JS;
}
if (ScriptLanguage.JS.equals(scriptLang)) {
engine = new RuleNodeJsScriptEngine(getTenantId(), jsInvokeService, script, argNames);
} else {
if (mvelInvokeService == null) {
throw new IllegalArgumentException("MVEL script engine is disabled!");
}
engine = new RuleNodeMvelScriptEngine(getTenantId(), mvelInvokeService, script, argNames);
}
TbMsg inMsg = TbMsg.newMsg(msgType, null, new TbMsgMetaData(metadata), TbMsgDataType.JSON, data);
switch (scriptType) {
case "update":

View File

@ -40,9 +40,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"If <b>True</b> - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used." +
"Message payload can be accessed via <code>msg</code> property. For example <code>msg.temperature < 10;</code><br/>" +
"Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
"Message type can be accessed via <code>msgType</code> property."
// uiResources = {"static/rulenode/rulenode-core-config.js"},
// configDirective = "tbFilterNodeScriptConfig")
"Message type can be accessed via <code>msgType</code> property.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeScriptConfig"
)
public class TbJsFilterNode implements TbNode {

View File

@ -40,9 +40,9 @@ import java.util.List;
"<code>msgType</code> - is a Message type.<br/>" +
"Should return the following structure:<br/>" +
"<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>&nbsp&nbsp&nbspmetadata: <i style=\"color: #666;\">new metadata</i>,<br/>&nbsp&nbsp&nbspmsgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" +
"All fields in resulting object are optional and will be taken from original message if not specified."
// uiResources = {"static/rulenode/rulenode-core-config.js"},
// configDirective = "tbTransformationNodeScriptConfig"
"All fields in resulting object are optional and will be taken from original message if not specified.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbTransformationNodeScriptConfig"
)
public class TbTransformMsgNode extends TbAbstractTransformNode {

View File

@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.script.ScriptLanguage;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -180,7 +181,7 @@ public class TbAlarmNodeTest {
verifyError(msg, "message", NotImplementedException.class);
verify(ctx).createJsScriptEngine("DETAILS");
verify(ctx).createScriptEngine(ScriptLanguage.JS, "DETAILS");
verify(ctx).getAlarmService();
verify(ctx, times(3)).getDbCallbackExecutor();
verify(ctx).logJsEvalRequest();
@ -395,12 +396,13 @@ public class TbAlarmNodeTest {
config.setPropagate(true);
config.setSeverity("$[alarmSeverity]");
config.setAlarmType("SomeType");
config.setScriptLang(ScriptLanguage.JS);
config.setAlarmDetailsBuildJs("DETAILS");
config.setDynamicSeverity(true);
ObjectMapper mapper = new ObjectMapper();
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs);
when(ctx.createScriptEngine(ScriptLanguage.JS, "DETAILS")).thenReturn(detailsJs);
when(ctx.getTenantId()).thenReturn(tenantId);
when(ctx.getAlarmService()).thenReturn(alarmService);
@ -456,6 +458,7 @@ public class TbAlarmNodeTest {
public void testCreateAlarmWithDynamicSeverityFromMetadata() throws Exception {
TbCreateAlarmNodeConfiguration config = new TbCreateAlarmNodeConfiguration();
config.setPropagate(true);
config.setScriptLang(ScriptLanguage.JS);
config.setSeverity("${alarmSeverity}");
config.setAlarmType("SomeType");
config.setAlarmDetailsBuildJs("DETAILS");
@ -463,7 +466,7 @@ public class TbAlarmNodeTest {
ObjectMapper mapper = new ObjectMapper();
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs);
when(ctx.createScriptEngine(ScriptLanguage.JS, "DETAILS")).thenReturn(detailsJs);
when(ctx.getTenantId()).thenReturn(tenantId);
when(ctx.getAlarmService()).thenReturn(alarmService);
@ -521,12 +524,13 @@ public class TbAlarmNodeTest {
config.setPropagateToTenant(true);
config.setSeverity(CRITICAL.name());
config.setAlarmType("SomeType" + i);
config.setScriptLang(ScriptLanguage.JS);
config.setAlarmDetailsBuildJs("DETAILS");
config.setDynamicSeverity(true);
ObjectMapper mapper = new ObjectMapper();
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs);
when(ctx.createScriptEngine(ScriptLanguage.JS, "DETAILS")).thenReturn(detailsJs);
when(ctx.getTenantId()).thenReturn(tenantId);
when(ctx.getAlarmService()).thenReturn(alarmService);
@ -584,11 +588,12 @@ public class TbAlarmNodeTest {
config.setPropagate(true);
config.setSeverity(CRITICAL.name());
config.setAlarmType("SomeType");
config.setScriptLang(ScriptLanguage.JS);
config.setAlarmDetailsBuildJs("DETAILS");
ObjectMapper mapper = new ObjectMapper();
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs);
when(ctx.createScriptEngine(ScriptLanguage.JS, "DETAILS")).thenReturn(detailsJs);
when(ctx.getTenantId()).thenReturn(tenantId);
when(ctx.getAlarmService()).thenReturn(alarmService);
@ -605,11 +610,12 @@ public class TbAlarmNodeTest {
try {
TbClearAlarmNodeConfiguration config = new TbClearAlarmNodeConfiguration();
config.setAlarmType("SomeType");
config.setScriptLang(ScriptLanguage.JS);
config.setAlarmDetailsBuildJs("DETAILS");
ObjectMapper mapper = new ObjectMapper();
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
when(ctx.createJsScriptEngine("DETAILS")).thenReturn(detailsJs);
when(ctx.createScriptEngine(ScriptLanguage.JS, "DETAILS")).thenReturn(detailsJs);
when(ctx.getTenantId()).thenReturn(tenantId);
when(ctx.getAlarmService()).thenReturn(alarmService);

View File

@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.script.ScriptLanguage;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -54,8 +55,6 @@ public class TbJsFilterNodeTest {
@Mock
private TbContext ctx;
@Mock
private ListeningExecutor executor;
@Mock
private ScriptEngine scriptEngine;
private RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased());
@ -73,7 +72,7 @@ public class TbJsFilterNodeTest {
}
@Test
public void exceptionInJsThrowsException() throws TbNodeException, ScriptException {
public void exceptionInJsThrowsException() throws TbNodeException {
initWithScript();
TbMsgMetaData metaData = new TbMsgMetaData();
TbMsg msg = TbMsg.newMsg("USER", null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId);
@ -85,7 +84,7 @@ public class TbJsFilterNodeTest {
}
@Test
public void metadataConditionCanBeTrue() throws TbNodeException, ScriptException {
public void metadataConditionCanBeTrue() throws TbNodeException {
initWithScript();
TbMsgMetaData metaData = new TbMsgMetaData();
TbMsg msg = TbMsg.newMsg("USER", null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId);
@ -98,11 +97,12 @@ public class TbJsFilterNodeTest {
private void initWithScript() throws TbNodeException {
TbJsFilterNodeConfiguration config = new TbJsFilterNodeConfiguration();
config.setScriptLang(ScriptLanguage.JS);
config.setJsScript("scr");
ObjectMapper mapper = new ObjectMapper();
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
when(ctx.createJsScriptEngine("scr")).thenReturn(scriptEngine);
when(ctx.createScriptEngine(ScriptLanguage.JS, "scr")).thenReturn(scriptEngine);
node = new TbJsFilterNode();
node.init(ctx, nodeConfiguration);

View File

@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.script.ScriptLanguage;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -55,12 +56,10 @@ public class TbTransformMsgNodeTest {
@Mock
private TbContext ctx;
@Mock
private ListeningExecutor executor;
@Mock
private ScriptEngine scriptEngine;
@Test
public void metadataCanBeUpdated() throws TbNodeException, ScriptException {
public void metadataCanBeUpdated() throws TbNodeException {
initWithScript();
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("temp", "7");
@ -80,7 +79,7 @@ public class TbTransformMsgNodeTest {
}
@Test
public void exceptionHandledCorrectly() throws TbNodeException, ScriptException {
public void exceptionHandledCorrectly() throws TbNodeException {
initWithScript();
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("temp", "7");
@ -97,11 +96,12 @@ public class TbTransformMsgNodeTest {
private void initWithScript() throws TbNodeException {
TbTransformMsgNodeConfiguration config = new TbTransformMsgNodeConfiguration();
config.setScriptLang(ScriptLanguage.JS);
config.setJsScript("scr");
ObjectMapper mapper = new ObjectMapper();
TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
when(ctx.createJsScriptEngine("scr")).thenReturn(scriptEngine);
when(ctx.createScriptEngine(ScriptLanguage.JS, "scr")).thenReturn(scriptEngine);
node = new TbTransformMsgNode();
node.init(ctx, nodeConfiguration);