2  * ============LICENSE_START=======================================================
 
   3  * Copyright (C) 2020 Nordix Foundation.
 
   4  * ================================================================================
 
   5  * Licensed under the Apache License, Version 2.0 (the "License");
 
   6  * you may not use this file except in compliance with the License.
 
   7  * You may obtain a copy of the License at
 
   9  *      http://www.apache.org/licenses/LICENSE-2.0
 
  11  * Unless required by applicable law or agreed to in writing, software
 
  12  * distributed under the License is distributed on an "AS IS" BASIS,
 
  13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  14  * See the License for the specific language governing permissions and
 
  15  * limitations under the License.
 
  17  * SPDX-License-Identifier: Apache-2.0
 
  18  * ============LICENSE_END=========================================================
 
  21 package org.onap.policy.apex.plugins.executor.javascript;
 
  23 import static org.assertj.core.api.Assertions.assertThatCode;
 
  24 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
  25 import static org.awaitility.Awaitility.await;
 
  26 import static org.junit.Assert.assertFalse;
 
  27 import static org.junit.Assert.assertTrue;
 
  29 import java.io.IOException;
 
  30 import java.util.concurrent.TimeUnit;
 
  31 import java.util.concurrent.atomic.AtomicBoolean;
 
  32 import org.junit.Before;
 
  33 import org.junit.Test;
 
  34 import org.onap.policy.apex.core.engine.executor.exception.StateMachineException;
 
  35 import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
 
  36 import org.slf4j.ext.XLogger;
 
  37 import org.slf4j.ext.XLoggerFactory;
 
  39 public class JavascriptExecutorTest {
 
  40     private static final XLogger LOGGER = XLoggerFactory.getXLogger(JavascriptExecutorTest.class);
 
  42     private AtomicBoolean concurrentResult = new AtomicBoolean();
 
  45     public void beforeSetTimeouts() {
 
  46         JavascriptExecutor.setTimeunit4Latches(TimeUnit.SECONDS);
 
  47         JavascriptExecutor.setIntializationLatchTimeout(60);
 
  48         JavascriptExecutor.setCleanupLatchTimeout(10);
 
  52     public void testJavescriptExecutorConcurrencyNormal() throws StateMachineException, IOException {
 
  53         JavascriptExecutor.setTimeunit4Latches(TimeUnit.SECONDS);
 
  54         JavascriptExecutor.setIntializationLatchTimeout(60);
 
  55         JavascriptExecutor.setCleanupLatchTimeout(10);
 
  57         JavascriptExecutor executor = new JavascriptExecutor(new AxArtifactKey("executor:0.0.1"));
 
  59         assertThatThrownBy(() -> {
 
  61         }).hasMessageMatching("^javascriptCode is marked .*on.*ull but is null$");
 
  63         assertThatThrownBy(() -> {
 
  65         }).hasMessage("initiation failed, no logic specified for executor executor:0.0.1");
 
  67         assertThatCode(() -> {
 
  68             executor.init("var x = 1;");
 
  69         }).doesNotThrowAnyException();
 
  71         assertThatThrownBy(() -> {
 
  72             executor.init("var x = 1;");
 
  73         }).hasMessage("initiation failed, executor executor:0.0.1 already initialized, run cleanUp to clear executor");
 
  75         assertThatCode(() -> {
 
  77         }).doesNotThrowAnyException();
 
  79         assertThatThrownBy(() -> {
 
  81         }).hasMessage("cleanup failed, executor executor:0.0.1 is not initialized");
 
  83         assertThatThrownBy(() -> {
 
  84             executor.execute("Hello");
 
  85         }).hasMessage("execution failed, executor executor:0.0.1 is not initialized");
 
  87         assertThatCode(() -> {
 
  88             executor.init("var x = 1;");
 
  89         }).doesNotThrowAnyException();
 
  91         assertThatThrownBy(() -> {
 
  92             executor.execute("Hello");
 
  94             "execute: logic for executor:0.0.1 returned a non-boolean value org.mozilla.javascript.Undefined@0");
 
  96         assertThatThrownBy(() -> {
 
  97             executor.execute("Hello");
 
  99             "execute: logic for executor:0.0.1 returned a non-boolean value org.mozilla.javascript.Undefined@0");
 
 101         assertThatThrownBy(() -> {
 
 102             executor.execute("Hello");
 
 104             "execute: logic for executor:0.0.1 returned a non-boolean value org.mozilla.javascript.Undefined@0");
 
 106         assertThatThrownBy(() -> {
 
 107             executor.execute("Hello");
 
 109             "execute: logic for executor:0.0.1 returned a non-boolean value org.mozilla.javascript.Undefined@0");
 
 111         assertThatCode(() -> {
 
 113         }).doesNotThrowAnyException();
 
 115         assertThatThrownBy(() -> {
 
 117         }).hasMessage("cleanup failed, executor executor:0.0.1 is not initialized");
 
 119         assertThatThrownBy(() -> {
 
 120             executor.execute("hello");
 
 121         }).hasMessage("execution failed, executor executor:0.0.1 is not initialized");
 
 125     public void testJavescriptExecutorConcurrencyLatchTimeout() throws StateMachineException, IOException {
 
 126         JavascriptExecutor.setTimeunit4Latches(TimeUnit.MICROSECONDS);
 
 127         JavascriptExecutor.setIntializationLatchTimeout(1);
 
 128         JavascriptExecutor.setCleanupLatchTimeout(10000000);
 
 130         JavascriptExecutor executor = new JavascriptExecutor(new AxArtifactKey("executor:0.0.1"));
 
 132         assertThatThrownBy(() -> {
 
 133             executor.init("var x = 1;");
 
 134         }).hasMessage("JavascriptExecutor executor:0.0.1 initiation timed out after 1 MICROSECONDS");
 
 136         assertThatCode(() -> {
 
 138         }).doesNotThrowAnyException();
 
 140         JavascriptExecutor.setTimeunit4Latches(TimeUnit.SECONDS);
 
 141         JavascriptExecutor.setIntializationLatchTimeout(60);
 
 143         assertThatCode(() -> {
 
 144             executor.init("var x = 1;");
 
 145         }).doesNotThrowAnyException();
 
 147         assertThatCode(() -> {
 
 149         }).doesNotThrowAnyException();
 
 151         JavascriptExecutor.setTimeunit4Latches(TimeUnit.MICROSECONDS);
 
 152         JavascriptExecutor.setIntializationLatchTimeout(60000000);
 
 153         JavascriptExecutor.setCleanupLatchTimeout(1);
 
 155         assertThatCode(() -> {
 
 156             executor.init("var x = 1;");
 
 157         }).doesNotThrowAnyException();
 
 159         assertThatThrownBy(() -> {
 
 161         }).hasMessage("JavascriptExecutor executor:0.0.1 cleanup timed out after 1 MICROSECONDS");
 
 163         JavascriptExecutor.setCleanupLatchTimeout(10000000);
 
 164         assertThatThrownBy(() -> {
 
 166         }).hasMessage("cleanup failed, executor executor:0.0.1 is not initialized");
 
 168         assertThatCode(() -> {
 
 169             executor.init("var x = 1;");
 
 170         }).doesNotThrowAnyException();
 
 172         assertThatCode(() -> {
 
 174         }).doesNotThrowAnyException();
 
 178     public void testJavescriptExecutorBadStates() throws StateMachineException, IOException {
 
 179         JavascriptExecutor executor = new JavascriptExecutor(new AxArtifactKey("executor:0.0.1"));
 
 181         assertThatThrownBy(() -> {
 
 182             executor.execute("hello");
 
 183         }).hasMessage("execution failed, executor executor:0.0.1 is not initialized");
 
 185         assertThatThrownBy(() -> {
 
 187         }).hasMessage("cleanup failed, executor executor:0.0.1 is not initialized");
 
 189         assertThatCode(() -> {
 
 190             executor.init("var x = 1;");
 
 191         }).doesNotThrowAnyException();
 
 193         executor.getExecutorThread().interrupt();
 
 194         await().atMost(10, TimeUnit.SECONDS).until(() -> !executor.getExecutorThread().isAlive());
 
 196         assertThatThrownBy(() -> {
 
 197             executor.execute("hello");
 
 198         }).hasMessage("execution failed, executor executor:0.0.1 is not running, "
 
 199             + "run cleanUp to clear executor and init to restart executor");
 
 201         assertThatThrownBy(() -> {
 
 202             executor.execute("hello");
 
 203         }).hasMessage("execution failed, executor executor:0.0.1 is not running, "
 
 204             + "run cleanUp to clear executor and init to restart executor");
 
 206         assertThatCode(() -> {
 
 208         }).doesNotThrowAnyException();
 
 212     public void testJavescriptExecutorExecution() throws StateMachineException, IOException {
 
 213         JavascriptExecutor executor = new JavascriptExecutor(new AxArtifactKey("executor:0.0.1"));
 
 215         assertThatCode(() -> {
 
 216             executor.init("true;");
 
 217         }).doesNotThrowAnyException();
 
 219         assertThatCode(() -> {
 
 220             assertTrue(executor.execute("hello"));
 
 221         }).doesNotThrowAnyException();
 
 223         assertThatCode(() -> {
 
 225         }).doesNotThrowAnyException();
 
 227         assertThatCode(() -> {
 
 228             executor.init("false;");
 
 229         }).doesNotThrowAnyException();
 
 231         assertThatCode(() -> {
 
 232             assertFalse(executor.execute("hello"));
 
 233         }).doesNotThrowAnyException();
 
 235         assertThatCode(() -> {
 
 237         }).doesNotThrowAnyException();
 
 239         assertThatThrownBy(() -> {
 
 240             executor.init("aaaaa = \"sss");
 
 242             "logic failed to compile for executor:0.0.1 with message: unterminated string literal (executor:0.0.1#1)");
 
 244         assertThatCode(() -> {
 
 246         }).doesNotThrowAnyException();
 
 248         assertThatCode(() -> {
 
 249             executor.init("true;");
 
 250         }).doesNotThrowAnyException();
 
 252         assertThatCode(() -> {
 
 253             assertTrue(executor.execute("hello"));
 
 254         }).doesNotThrowAnyException();
 
 256         assertThatCode(() -> {
 
 258         }).doesNotThrowAnyException();
 
 260         assertThatCode(() -> {
 
 261             executor.init("throw \"this is an error\";");
 
 262         }).doesNotThrowAnyException();
 
 264         assertThatThrownBy(() -> {
 
 265             assertTrue(executor.execute("hello"));
 
 266         }).hasMessage("logic failed to run for executor:0.0.1 with message: this is an error (executor:0.0.1#1)");
 
 268         assertThatCode(() -> {
 
 270         }).doesNotThrowAnyException();
 
 272         assertThatCode(() -> {
 
 273             executor.init("var x = 0; while (x < 100) { x++; }; true;");
 
 274         }).doesNotThrowAnyException();
 
 276         concurrentResult.set(true);
 
 278         // Execute an infinite loop in Javascript
 
 282                     while (executor.execute("hello")) {
 
 283                         LOGGER.debug("test thread running . . .");
 
 284                         // Loop until interrupted
 
 286                 } catch (StateMachineException e) {
 
 287                     LOGGER.debug("test thread caught exception", e);
 
 289                 concurrentResult.set(false);
 
 290                 LOGGER.debug("test thread exited");
 
 294         await().atMost(1000, TimeUnit.MILLISECONDS).until(() -> executor.getExecutorThread().isAlive());
 
 296         executor.getExecutorThread().interrupt();
 
 298         await().atMost(1000, TimeUnit.MILLISECONDS).until(() -> !concurrentResult.get());
 
 300         assertThatCode(() -> {
 
 302         }).doesNotThrowAnyException();
 
 304         assertThatCode(() -> {
 
 305             executor.init("true;");
 
 306         }).doesNotThrowAnyException();
 
 308         assertThatCode(() -> {
 
 309             assertTrue(executor.execute("hello"));
 
 310         }).doesNotThrowAnyException();
 
 312         assertThatCode(() -> {
 
 314         }).doesNotThrowAnyException();
 
 316         assertThatCode(() -> {
 
 317             executor.init("x = 1; true;");
 
 318         }).doesNotThrowAnyException();
 
 320         concurrentResult.set(true);
 
 322         // Execute an infinite loop in Javascript
 
 323         Thread executionThread = new Thread() {
 
 326                     while (executor.execute("hello")) {
 
 329                 } catch (StateMachineException e) {
 
 334         executionThread.start();
 
 336         executionThread.interrupt();
 
 338         await().atMost(300, TimeUnit.MILLISECONDS).until(() -> !executionThread.isAlive());
 
 339         await().atMost(300, TimeUnit.MILLISECONDS).until(() -> !executor.getExecutorThread().isAlive());
 
 341         assertThatCode(() -> {
 
 343         }).doesNotThrowAnyException();