From 2f75e9d08d1e47e2b9b39ec21653bc3b4d65d00a Mon Sep 17 00:00:00 2001 From: liamfallon Date: Mon, 23 Mar 2020 17:49:50 +0000 Subject: Launch separate threads for Javascript task execution When a policy is loaded, a separate thread is spawned for each Javascript script executor. This allows us to precompile the Javascript scripts and also to have a larger stack available for script execution. Issue-ID: POLICY-2106 Change-Id: I97323aafb623ba537ac1889b3c9504b345b4f67e Signed-off-by: liamfallon --- .../main/resources/logic/MakeDecisionStateTSL.js | 6 +- .../resources/policy/DecisionMakerPolicyModel.apex | 26 +-- .../executor/javascript/JavascriptExecutor.java | 192 ++++++++++++++++++--- .../JavascriptStateFinalizerExecutor.java | 13 +- .../javascript/JavascriptTaskExecutor.java | 17 +- .../javascript/JavascriptTaskSelectExecutor.java | 16 +- .../JavascriptStateFinalizerExecutorTest.java | 54 ++++-- .../javascript/JavascriptTaskExecutorTest.java | 42 +++-- .../JavascriptTaskSelectExecutorTest.java | 35 ++-- .../src/test/resources/logback-test.xml | 41 +++++ 10 files changed, 346 insertions(+), 96 deletions(-) create mode 100644 plugins/plugins-executor/plugins-executor-javascript/src/test/resources/logback-test.xml diff --git a/examples/examples-decisionmaker/src/main/resources/logic/MakeDecisionStateTSL.js b/examples/examples-decisionmaker/src/main/resources/logic/MakeDecisionStateTSL.js index 33af49534..e49438d14 100644 --- a/examples/examples-decisionmaker/src/main/resources/logic/MakeDecisionStateTSL.js +++ b/examples/examples-decisionmaker/src/main/resources/logic/MakeDecisionStateTSL.js @@ -34,9 +34,9 @@ else if (executor.inFields.get("mode").equals("optimistic")) { else if (executor.inFields.get("mode").equals("dithering")) { executor.subject.getTaskKey("DitheringAnswerTask").copyTo(executor.selectedTask); } -//else if (executor.inFields.get("mode").equals("roundrobin")) { -// executor.subject.getTaskKey("RoundRobinAnswerTask").copyTo(executor.selectedTask); -//} +else if (executor.inFields.get("mode").equals("roundrobin")) { + executor.subject.getTaskKey("RoundRobinAnswerTask").copyTo(executor.selectedTask); +} executor.logger.info("Answer Selected Task:" + executor.selectedTask); diff --git a/examples/examples-decisionmaker/src/main/resources/policy/DecisionMakerPolicyModel.apex b/examples/examples-decisionmaker/src/main/resources/policy/DecisionMakerPolicyModel.apex index 295afa159..672ff894f 100644 --- a/examples/examples-decisionmaker/src/main/resources/policy/DecisionMakerPolicyModel.apex +++ b/examples/examples-decisionmaker/src/main/resources/policy/DecisionMakerPolicyModel.apex @@ -113,18 +113,18 @@ task logic create name=DitheringAnswerTask logicFlavour=JAVASCRIPT logic=LS #MACROFILE:"src/main/resources/logic/DitheringAnswerTask.js" LE -#task create name=RoundRobinAnswerTask -# -#task inputfield create name=RoundRobinAnswerTask fieldName=mode schemaName=SimpleStringType -# -#task outputfield create name=RoundRobinAnswerTask fieldName=decision schemaName=SimpleStringType -# -#task contextref create name=RoundRobinAnswerTask albumName=AnswerAlbum -#task contextref create name=RoundRobinAnswerTask albumName=LastAnswerAlbum -# -#task logic create name=RoundRobinAnswerTask logicFlavour=JAVASCRIPT logic=LS -##MACROFILE:"src/main/resources/logic/RoundRobinAnswerTask.js" -#LE +task create name=RoundRobinAnswerTask + +task inputfield create name=RoundRobinAnswerTask fieldName=mode schemaName=SimpleStringType + +task outputfield create name=RoundRobinAnswerTask fieldName=decision schemaName=SimpleStringType + +task contextref create name=RoundRobinAnswerTask albumName=AnswerAlbum +task contextref create name=RoundRobinAnswerTask albumName=LastAnswerAlbum + +task logic create name=RoundRobinAnswerTask logicFlavour=JAVASCRIPT logic=LS +#MACROFILE:"src/main/resources/logic/RoundRobinAnswerTask.js" +LE policy create name=AnswerInitPolicy template=freestyle firstState=AnswerInitState @@ -140,7 +140,7 @@ policy state taskref create name=DecisionMakerPolicy stateName=MakeDecisionState policy state taskref create name=DecisionMakerPolicy stateName=MakeDecisionState taskName=PessimisticAnswerTask outputType=DIRECT outputName=DecisionFinalOutput policy state taskref create name=DecisionMakerPolicy stateName=MakeDecisionState taskName=OptimisticAnswerTask outputType=DIRECT outputName=DecisionFinalOutput policy state taskref create name=DecisionMakerPolicy stateName=MakeDecisionState taskName=DitheringAnswerTask outputType=DIRECT outputName=DecisionFinalOutput -#policy state taskref create name=DecisionMakerPolicy stateName=MakeDecisionState taskName=RoundRobinAnswerTask outputType=DIRECT outputName=DecisionFinalOutput +policy state taskref create name=DecisionMakerPolicy stateName=MakeDecisionState taskName=RoundRobinAnswerTask outputType=DIRECT outputName=DecisionFinalOutput policy state selecttasklogic create name=DecisionMakerPolicy stateName=MakeDecisionState logicFlavour=JAVASCRIPT logic=LS #MACROFILE:"src/main/resources/logic/MakeDecisionStateTSL.js" diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java index c80f58fbe..2394b83d3 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptExecutor.java @@ -20,19 +20,28 @@ package org.onap.policy.apex.plugins.executor.javascript; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicReference; + import org.apache.commons.lang3.StringUtils; import org.mozilla.javascript.Context; import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.onap.policy.apex.core.engine.executor.exception.StateMachineException; import org.onap.policy.apex.model.basicmodel.concepts.AxKey; +import org.slf4j.ext.XLogger; +import org.slf4j.ext.XLoggerFactory; /** * The Class JavascriptExecutor is the executor for task logic written in Javascript. * * @author Liam Fallon (liam.fallon@ericsson.com) */ -public class JavascriptExecutor { +public class JavascriptExecutor implements Runnable { + private static final XLogger LOGGER = XLoggerFactory.getXLogger(JavascriptExecutor.class); + public static final int DEFAULT_OPTIMIZATION_LEVEL = 9; // Recurring string constants @@ -41,16 +50,28 @@ public class JavascriptExecutor { // The key of the subject that wants to execute Javascript code final AxKey subjectKey; + private String javascriptCode; private Context javascriptContext; private Script script; + private final BlockingQueue executionQueue = new LinkedBlockingQueue<>(); + private final BlockingQueue resultQueue = new LinkedBlockingQueue<>(); + + private final Thread executorThread; + private CountDownLatch intializationLatch = new CountDownLatch(1); + private CountDownLatch shutdownLatch = new CountDownLatch(1); + private AtomicReference executorException = new AtomicReference<>(null); + /** - * Initializes the Javascripe executor. + * Initializes the Javascript executor. * * @param subjectKey the key of the subject that is requesting Javascript execution */ public JavascriptExecutor(final AxKey subjectKey) { this.subjectKey = subjectKey; + + executorThread = new Thread(this); + executorThread.setName(this.getClass().getSimpleName() + ":" + subjectKey.getId()); } /** @@ -60,10 +81,143 @@ public class JavascriptExecutor { * @throws StateMachineException thrown when instantiation of the executor fails */ public void init(final String javascriptCode) throws StateMachineException { + LOGGER.debug("JavascriptExecutor {} starting ... ", subjectKey.getId()); + + if (executorThread.isAlive()) { + throw new StateMachineException( + "initiation failed, executor " + subjectKey.getId() + " is already running"); + } + if (StringUtils.isEmpty(javascriptCode)) { throw new StateMachineException("no logic specified for " + subjectKey.getId()); } + this.javascriptCode = javascriptCode; + + try { + executorThread.start(); + } catch (Exception e) { + throw new StateMachineException("initiation failed, executor " + subjectKey.getId() + " failed to start", + e); + } + + try { + intializationLatch.await(); + } catch (InterruptedException e) { + LOGGER.debug("JavascriptExecutor {} interrupted on execution thread startup", subjectKey.getId(), e); + Thread.currentThread().interrupt(); + } + + if (executorException.get() != null) { + clearAndThrowExecutorException(); + } + + LOGGER.debug("JavascriptExecutor {} started ... ", subjectKey.getId()); + } + + /** + * Execute a Javascript script. + * + * @param executionContext the execution context to use for script execution + * @return true if execution was successful, false otherwise + * @throws StateMachineException on execution errors + */ + public boolean execute(final Object executionContext) throws StateMachineException { + if (!executorThread.isAlive()) { + throw new StateMachineException("execution failed, executor " + subjectKey.getId() + " is not running"); + } + + executionQueue.add(executionContext); + + boolean result = false; + + try { + result = resultQueue.take(); + } catch (final InterruptedException e) { + LOGGER.debug("JavascriptExecutor {} interrupted on execution result wait", subjectKey.getId(), e); + Thread.currentThread().interrupt(); + } + + if (executorException.get() != null) { + clearAndThrowExecutorException(); + } + + return result; + } + + /** + * Cleans up the executor after processing. + * + * @throws StateMachineException thrown when cleanup of the executor fails + */ + public void cleanUp() throws StateMachineException { + if (!executorThread.isAlive()) { + throw new StateMachineException("cleanup failed, executor " + subjectKey.getId() + " is not running"); + } + + executorThread.interrupt(); + + try { + shutdownLatch.await(); + } catch (InterruptedException e) { + LOGGER.debug("JavascriptExecutor {} interrupted on execution clkeanup wait", subjectKey.getId(), e); + Thread.currentThread().interrupt(); + } + + if (executorException.get() != null) { + clearAndThrowExecutorException(); + } + } + + @Override + public void run() { + LOGGER.debug("JavascriptExecutor {} initializing ... ", subjectKey.getId()); + + try { + initExecutor(); + } catch (StateMachineException sme) { + LOGGER.warn("JavascriptExecutor {} initialization failed", sme); + executorException.set(sme); + intializationLatch.countDown(); + return; + } + + intializationLatch.countDown(); + + LOGGER.debug("JavascriptExecutor {} executing ... ", subjectKey.getId()); + + // Take jobs from the execution queue of the worker and execute them + while (!executorThread.isInterrupted()) { + try { + Object contextObject = executionQueue.take(); + if (contextObject == null) { + break; + } + + resultQueue.add(executeScript(contextObject)); + } catch (final InterruptedException e) { + LOGGER.debug("execution was interruped for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e); + resultQueue.add(false); + Thread.currentThread().interrupt(); + } catch (StateMachineException sme) { + executorException.set(sme); + resultQueue.add(false); + } + } + + try { + Context.exit(); + } catch (final Exception e) { + executorException.set(new StateMachineException( + "executor close failed to close for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e)); + } + + shutdownLatch.countDown(); + + LOGGER.debug("JavascriptExecutor {} completed processing", subjectKey.getId()); + } + + private void initExecutor() throws StateMachineException { try { // Create a Javascript context for this thread javascriptContext = Context.enter(); @@ -76,18 +230,11 @@ public class JavascriptExecutor { } catch (Exception e) { Context.exit(); throw new StateMachineException( - "logic failed to compile for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e); + "logic failed to compile for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e); } } - /** - * Executes the the Javascript code. - * - * @param executionContext the execution context of the subject to be passed to the Javascript context - * @return true if the Javascript executed properly - * @throws StateMachineException thrown when Javascript execution fails - */ - public boolean execute(final Object executionContext) throws StateMachineException { + private boolean executeScript(final Object executionContext) throws StateMachineException { Object returnObject = null; try { @@ -99,28 +246,25 @@ public class JavascriptExecutor { returnObject = script.exec(javascriptContext, javascriptScope); } catch (final Exception e) { throw new StateMachineException( - "logic failed to run for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e); + "logic failed to run for " + subjectKey.getId() + WITH_MESSAGE + e.getMessage(), e); } if (!(returnObject instanceof Boolean)) { throw new StateMachineException( - "execute: logic for " + subjectKey.getId() + " returned a non-boolean value " + returnObject); + "execute: logic for " + subjectKey.getId() + " returned a non-boolean value " + returnObject); } return (boolean) returnObject; } - /** - * Cleans up the executor after processing. - * - * @throws StateMachineException thrown when cleanup of the executor fails - */ - public void cleanUp() throws StateMachineException { - try { - Context.exit(); - } catch (final Exception e) { - throw new StateMachineException("cleanUp: executor cleanup failed to close for " + subjectKey.getId() - + WITH_MESSAGE + e.getMessage(), e); + private void clearAndThrowExecutorException() throws StateMachineException { + StateMachineException exceptionToThrow = executorException.getAndSet(null); + if (exceptionToThrow != null) { + throw exceptionToThrow; } } + + protected Thread getExecutorThread() { + return executorThread; + } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java index 27e649fd3..63e4948dd 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutor.java @@ -53,11 +53,12 @@ public class JavascriptStateFinalizerExecutor extends StateFinalizerExecutor { super.prepare(); // Create the executor - javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + if (javascriptExecutor == null) { + javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + } // Initialize and cleanup the executor to check the Javascript code javascriptExecutor.init(getSubject().getLogic()); - javascriptExecutor.cleanUp(); } /** @@ -72,14 +73,12 @@ public class JavascriptStateFinalizerExecutor extends StateFinalizerExecutor { */ @Override public String execute(final long executionId, final Properties executionProperties, - final Map incomingFields) throws StateMachineException, ContextException { + final Map incomingFields) throws StateMachineException, ContextException { // Do execution pre work executePre(executionId, executionProperties, incomingFields); // Execute the Javascript executor - javascriptExecutor.init(getSubject().getLogic()); boolean result = javascriptExecutor.execute(getExecutionContext()); - javascriptExecutor.cleanUp(); // Execute the Javascript executePost(result); @@ -95,6 +94,8 @@ public class JavascriptStateFinalizerExecutor extends StateFinalizerExecutor { @Override public void cleanUp() throws StateMachineException { LOGGER.debug("cleanUp:" + getSubject().getKey().getId() + "," + getSubject().getLogicFlavour() + "," - + getSubject().getLogic()); + + getSubject().getLogic()); + + javascriptExecutor.cleanUp(); } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java index bec5670c5..a9dba27f2 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutor.java @@ -53,11 +53,12 @@ public class JavascriptTaskExecutor extends TaskExecutor { super.prepare(); // Create the executor - javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + if (javascriptExecutor == null) { + javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + } // Initialize and cleanup the executor to check the Javascript code javascriptExecutor.init(getSubject().getTaskLogic().getLogic()); - javascriptExecutor.cleanUp(); } /** @@ -72,15 +73,13 @@ public class JavascriptTaskExecutor extends TaskExecutor { */ @Override public Map execute(final long executionId, final Properties executionProperties, - final Map incomingFields) throws StateMachineException, ContextException { + final Map incomingFields) throws StateMachineException, ContextException { // Do execution pre work executePre(executionId, executionProperties, incomingFields); // Execute the Javascript executor - javascriptExecutor.init(getSubject().getTaskLogic().getLogic()); boolean result = javascriptExecutor.execute(getExecutionContext()); - javascriptExecutor.cleanUp(); // Execute the Javascript executePost(result); @@ -96,6 +95,12 @@ public class JavascriptTaskExecutor extends TaskExecutor { @Override public void cleanUp() throws StateMachineException { LOGGER.debug("cleanUp:" + getSubject().getKey().getId() + "," + getSubject().getTaskLogic().getLogicFlavour() - + "," + getSubject().getTaskLogic().getLogic()); + + "," + getSubject().getTaskLogic().getLogic()); + + if (javascriptExecutor != null) { + javascriptExecutor.cleanUp(); + } + + javascriptExecutor = null; } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java index c32b70991..93384c129 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/main/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutor.java @@ -54,7 +54,9 @@ public class JavascriptTaskSelectExecutor extends TaskSelectExecutor { super.prepare(); // Create the executor - javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + if (javascriptExecutor == null) { + javascriptExecutor = new JavascriptExecutor(getSubject().getKey()); + } // Initialize and cleanup the executor to check the Javascript code javascriptExecutor.init(getSubject().getTaskSelectionLogic().getLogic()); @@ -72,14 +74,12 @@ public class JavascriptTaskSelectExecutor extends TaskSelectExecutor { */ @Override public AxArtifactKey execute(final long executionId, final Properties executionProperties, - final EnEvent incomingEvent) throws StateMachineException, ContextException { + final EnEvent incomingEvent) throws StateMachineException, ContextException { // Do execution pre work executePre(executionId, executionProperties, incomingEvent); // Execute the Javascript executor - javascriptExecutor.init(getSubject().getTaskSelectionLogic().getLogic()); boolean result = javascriptExecutor.execute(getExecutionContext()); - javascriptExecutor.cleanUp(); // Execute the Javascript executePost(result); @@ -94,8 +94,10 @@ public class JavascriptTaskSelectExecutor extends TaskSelectExecutor { */ @Override public void cleanUp() throws StateMachineException { - LOGGER.debug("cleanUp:" + getSubject().getKey().getId() + "," - + getSubject().getTaskSelectionLogic().getLogicFlavour() + "," - + getSubject().getTaskSelectionLogic().getLogic()); + LOGGER.debug( + "cleanUp:" + getSubject().getKey().getId() + "," + getSubject().getTaskSelectionLogic().getLogicFlavour() + + "," + getSubject().getTaskSelectionLogic().getLogic()); + + javascriptExecutor.cleanUp(); } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutorTest.java b/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutorTest.java index 8be79558f..d4a346187 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutorTest.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptStateFinalizerExecutorTest.java @@ -20,6 +20,7 @@ package org.onap.policy.apex.plugins.executor.javascript; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -96,36 +97,59 @@ public class JavascriptStateFinalizerExecutorTest { assertThatThrownBy(() -> { jsfe.prepare(); }).hasMessage("logic failed to compile for NULL:0.0.0:NULL:NULL " - + "with message: invalid return (NULL:0.0.0:NULL:NULL#1)"); + + "with message: invalid return (NULL:0.0.0:NULL:NULL#1)"); Map incomingParameters1 = new HashMap<>(); assertThatThrownBy(() -> { jsfe.execute(-1, new Properties(), incomingParameters1); - }).hasMessage("logic failed to compile for NULL:0.0.0:NULL:NULL " - + "with message: invalid return (NULL:0.0.0:NULL:NULL#1)"); + }).hasMessage("execution failed, executor NULL:0.0.0:NULL:NULL is not running"); + + assertThatThrownBy(() -> { + jsfe.prepare(); + }).hasMessage("initiation failed, executor NULL:0.0.0:NULL:NULL failed to start"); + assertThatThrownBy(() -> { + jsfe.cleanUp(); + }).hasMessage("cleanup failed, executor NULL:0.0.0:NULL:NULL is not running"); + + JavascriptStateFinalizerExecutor jsfe1 = new JavascriptStateFinalizerExecutor(); stateFinalizerLogic.setLogic("java.lang.String"); - jsfe.prepare(); + jsfe1.setContext(parentStateExcutor, stateFinalizerLogic, internalContext); + jsfe1.prepare(); AxEvent axEvent = new AxEvent(new AxArtifactKey("Event", "0.0.1")); EnEvent event = new EnEvent(axEvent); - stateFinalizerLogic.setLogic("if(executor.executionId==-1)" + "{\r\n" - + "var returnValueType = java.lang.Boolean;" + "var returnValue = new returnValueType(false); }\n" - + "else{\n" + "executor.setSelectedStateOutputName(\"SelectedOutputIsMe\");\n" - + "var returnValueType = java.lang.Boolean;\n" + "\n" - + "var returnValue = new returnValueType(true);} true;"); assertThatThrownBy(() -> { - jsfe.prepare(); - jsfe.execute(-1, new Properties(), event); - }).hasMessage("execute-post: state finalizer logic \"NULL:0.0.0:NULL:NULL\" did not select an output state"); + jsfe1.execute(-1, new Properties(), event); + }).hasMessage( + "execute: logic for NULL:0.0.0:NULL:NULL returned a non-boolean value [JavaClass java.lang.String]"); + + assertThatThrownBy(() -> { + jsfe1.execute(-1, new Properties(), event); + }).hasMessage( + "execute: logic for NULL:0.0.0:NULL:NULL returned a non-boolean value [JavaClass java.lang.String]"); + + assertThatCode(() -> { + jsfe1.cleanUp(); + }).doesNotThrowAnyException(); + + JavascriptStateFinalizerExecutor jsfe2 = new JavascriptStateFinalizerExecutor(); + + stateFinalizerLogic.setLogic("executor.setSelectedStateOutputName(\"SelectedOutputIsMe\");\n true;"); + + jsfe2.setContext(parentStateExcutor, stateFinalizerLogic, internalContext); + assertThatCode(() -> { + jsfe2.prepare(); + }).doesNotThrowAnyException(); state.getStateOutputs().put("SelectedOutputIsMe", null); - jsfe.prepare(); - String stateOutput = jsfe.execute(0, new Properties(), event); + String stateOutput = jsfe2.execute(0, new Properties(), event); assertEquals("SelectedOutputIsMe", stateOutput); - jsfe.cleanUp(); + assertThatCode(() -> { + jsfe2.cleanUp(); + }).doesNotThrowAnyException(); } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutorTest.java b/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutorTest.java index c327ebb4d..b532d6c47 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutorTest.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskExecutorTest.java @@ -20,6 +20,7 @@ package org.onap.policy.apex.plugins.executor.javascript; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -64,7 +65,7 @@ public class JavascriptTaskExecutorTest { public static void prepareForTest() { final ContextParameters contextParameters = new ContextParameters(); contextParameters.getLockManagerParameters() - .setPluginClass("org.onap.policy.apex.context.impl.locking.jvmlocal.JvmLocalLockManager"); + .setPluginClass("org.onap.policy.apex.context.impl.locking.jvmlocal.JvmLocalLockManager"); contextParameters.setName(ContextParameterConstants.MAIN_GROUP_NAME); contextParameters.getDistributorParameters().setName(ContextParameterConstants.DISTRIBUTOR_GROUP_NAME); @@ -98,32 +99,47 @@ public class JavascriptTaskExecutorTest { @Test public void testJavascriptTaskExecutor() throws Exception { - JavascriptTaskExecutor jte = new JavascriptTaskExecutor(); - assertNotNull(jte); - assertThatThrownBy(() -> { - jte.prepare(); + JavascriptTaskExecutor jteBadPrep = new JavascriptTaskExecutor(); + jteBadPrep.prepare(); }).isInstanceOf(NullPointerException.class); AxTask task = new AxTask(new AxArtifactKey("TestTask:0.0.1")); final ApexInternalContext internalContext = new ApexInternalContext(new AxPolicyModel()); - jte.setContext(null, task, internalContext); + JavascriptTaskExecutor jteBadLogic = new JavascriptTaskExecutor(); + assertNotNull(jteBadLogic); + + jteBadLogic.setContext(null, task, internalContext); task.getTaskLogic().setLogic("return boolean;"); assertThatThrownBy(() -> { - jte.prepare(); - jte.execute(-1, new Properties(), null); + jteBadLogic.prepare(); }).hasMessage("logic failed to compile for TestTask:0.0.1 with message: invalid return (TestTask:0.0.1#1)"); task.getTaskLogic().setLogic("var x = 5;"); + JavascriptTaskExecutor jte = new JavascriptTaskExecutor(); + jte.setContext(null, task, internalContext); + jte.prepare(); + + assertThatThrownBy(() -> { + jte.prepare(); + }).hasMessage("initiation failed, executor TestTask:0.0.1 is already running"); + assertThatThrownBy(() -> { jte.execute(-1, new Properties(), null); }).isInstanceOf(NullPointerException.class); - jte.cleanUp(); + + assertThatThrownBy(() -> { + jte.execute(-1, new Properties(), null); + }).isInstanceOf(NullPointerException.class); + + assertThatCode(() -> { + jte.cleanUp(); + }).doesNotThrowAnyException(); task.getTaskLogic().setLogic("var returnValue = false;\nreturnValue;"); @@ -142,6 +158,10 @@ public class JavascriptTaskExecutorTest { Map returnMap = jte.execute(0, new Properties(), incomingParameters); assertEquals(0, returnMap.size()); jte.cleanUp(); + + assertThatCode(() -> { + jte.cleanUp(); + }).doesNotThrowAnyException(); } @Test @@ -188,12 +208,12 @@ public class JavascriptTaskExecutorTest { private ContextAlbum createTestContextAlbum() throws ContextException { AxContextSchemas schemas = new AxContextSchemas(); AxContextSchema simpleStringSchema = - new AxContextSchema(new AxArtifactKey("SimpleStringSchema", "0.0.1"), "JAVA", "java.lang.String"); + new AxContextSchema(new AxArtifactKey("SimpleStringSchema", "0.0.1"), "JAVA", "java.lang.String"); schemas.getSchemasMap().put(simpleStringSchema.getKey(), simpleStringSchema); ModelService.registerModel(AxContextSchemas.class, schemas); AxContextAlbum axContextAlbum = new AxContextAlbum(new AxArtifactKey("TestContextAlbum", "0.0.1"), "Policy", - true, AxArtifactKey.getNullKey()); + true, AxArtifactKey.getNullKey()); axContextAlbum.setItemSchema(simpleStringSchema.getKey()); Distributor distributor = new JvmLocalDistributor(); diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutorTest.java b/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutorTest.java index 3acf132dd..cb577535a 100644 --- a/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutorTest.java +++ b/plugins/plugins-executor/plugins-executor-javascript/src/test/java/org/onap/policy/apex/plugins/executor/javascript/JavascriptTaskSelectExecutorTest.java @@ -20,6 +20,7 @@ package org.onap.policy.apex.plugins.executor.javascript; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -90,7 +91,7 @@ public class JavascriptTaskSelectExecutorTest { assertThatThrownBy(() -> { jtse.execute(-1, new Properties(), event1); - }).hasMessage("no logic specified for NULL:0.0.0:NULL:NULL"); + }).hasMessage("execution failed, executor NULL:0.0.0:NULL:NULL is not running"); state.getTaskSelectionLogic().setLogic("java.lang.String"); jtse.prepare(); @@ -105,20 +106,32 @@ public class JavascriptTaskSelectExecutorTest { assertThatThrownBy(() -> { jtse.execute(-1, new Properties(), event); }).hasMessage( - "execute: logic for NULL:0.0.0:NULL:NULL returned a non-boolean value [JavaClass java.lang.String]"); + "execute: logic for NULL:0.0.0:NULL:NULL returned a non-boolean value [JavaClass java.lang.String]"); - state.getTaskSelectionLogic().setLogic("var x=1;\n" + "false; "); + state.getTaskSelectionLogic().setLogic("var x=1;\n" + "false;"); assertThatThrownBy(() -> { - jtse.prepare(); jtse.execute(-1, new Properties(), event); - }).hasMessage("execute-post: task selection logic failed on state \"NULL:0.0.0:NULL:NULL\""); - - state.getTaskSelectionLogic().setLogic("var x = 1\n" + "true; "); + }).hasMessage( + "execute: logic for NULL:0.0.0:NULL:NULL returned a non-boolean value [JavaClass java.lang.String]"); - jtse.prepare(); - AxArtifactKey taskKey = jtse.execute(0, new Properties(), event); - assertEquals("NULL:0.0.0", taskKey.getId()); - jtse.cleanUp(); + assertThatThrownBy(() -> { + jtse.prepare(); + }).hasMessage("initiation failed, executor NULL:0.0.0:NULL:NULL is already running"); + + assertThatCode(() -> { + jtse.cleanUp(); + }).doesNotThrowAnyException(); + + JavascriptTaskSelectExecutor jtse1 = new JavascriptTaskSelectExecutor(); + jtse1.setContext(null, state, internalContext); + state.getTaskSelectionLogic().setLogic("var x = 1\n" + "true;"); + + assertThatCode(() -> { + jtse1.prepare(); + AxArtifactKey taskKey = jtse1.execute(0, new Properties(), event); + assertEquals("NULL:0.0.0", taskKey.getId()); + jtse1.cleanUp(); + }).doesNotThrowAnyException(); } } diff --git a/plugins/plugins-executor/plugins-executor-javascript/src/test/resources/logback-test.xml b/plugins/plugins-executor/plugins-executor-javascript/src/test/resources/logback-test.xml new file mode 100644 index 000000000..f3bc0c8ed --- /dev/null +++ b/plugins/plugins-executor/plugins-executor-javascript/src/test/resources/logback-test.xml @@ -0,0 +1,41 @@ + + + + + Apex + + + + + + %d %contextName [%t] %level %logger{36} - %msg%n + + + + + + + + + + + -- cgit 1.2.3-korg