diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutor.java new file mode 100644 index 00000000..1f456e10 --- /dev/null +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutor.java @@ -0,0 +1,127 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors; + +import io.serverlessworkflow.api.types.RunScript; +import io.serverlessworkflow.api.types.RunTaskConfiguration; +import io.serverlessworkflow.api.types.Script; +import io.serverlessworkflow.api.types.ScriptUnion; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowDefinition; +import io.serverlessworkflow.impl.WorkflowModel; +import io.serverlessworkflow.impl.WorkflowUtils; +import io.serverlessworkflow.impl.WorkflowValueResolver; +import io.serverlessworkflow.impl.resources.ResourceLoaderUtils; +import io.serverlessworkflow.impl.scripts.ScriptContext; +import io.serverlessworkflow.impl.scripts.ScriptLanguageId; +import io.serverlessworkflow.impl.scripts.ScriptRunner; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.concurrent.CompletableFuture; + +public class RunScriptExecutor implements RunnableTask { + + private Optional>> environmentExpr; + + private Optional>> argumentExpr; + + private WorkflowValueResolver codeSupplier; + private boolean isAwait; + private RunTaskConfiguration.ProcessReturnType returnType; + private ScriptRunner taskRunner; + + @Override + public void init(RunScript taskConfiguration, WorkflowDefinition definition) { + ScriptUnion scriptUnion = taskConfiguration.getScript(); + Script script = scriptUnion.get(); + ScriptLanguageId language = ScriptLanguageId.from(script.getLanguage()); + + this.taskRunner = + ServiceLoader.load(ScriptRunner.class).stream() + .map(ServiceLoader.Provider::get) + .filter(s -> s.identifier().equals(language)) + .findFirst() + .orElseThrow( + () -> + new IllegalStateException( + "No script runner implementation found for language " + language)); + + this.isAwait = taskConfiguration.isAwait(); + + this.returnType = taskConfiguration.getReturn(); + + WorkflowApplication application = definition.application(); + this.environmentExpr = + script.getEnvironment() != null && script.getEnvironment().getAdditionalProperties() != null + ? Optional.of( + WorkflowUtils.buildMapResolver( + application, null, script.getEnvironment().getAdditionalProperties())) + : Optional.empty(); + + this.argumentExpr = + script.getArguments() != null && script.getArguments().getAdditionalProperties() != null + ? Optional.of( + WorkflowUtils.buildMapResolver( + application, null, script.getArguments().getAdditionalProperties())) + : Optional.empty(); + + this.codeSupplier = + scriptUnion.getInlineScript() != null + ? WorkflowUtils.buildStringFilter(application, scriptUnion.getInlineScript().getCode()) + : (w, t, m) -> + definition + .resourceLoader() + .load( + Objects.requireNonNull( + scriptUnion.getExternalScript(), + "External script is required if inline script was not set") + .getSource(), + ResourceLoaderUtils::readString, + w, + t, + m); + } + + @Override + public CompletableFuture apply( + WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input) { + return CompletableFuture.supplyAsync( + () -> + taskRunner.runScript( + new ScriptContext( + argumentExpr + .map(m -> m.apply(workflowContext, taskContext, input)) + .orElse(Map.of()), + environmentExpr + .map(m -> m.apply(workflowContext, taskContext, input)) + .orElse(Map.of()), + codeSupplier.apply(workflowContext, taskContext, input), + isAwait, + returnType), + workflowContext, + taskContext, + input)); + } + + @Override + public boolean accept(Class clazz) { + return RunScript.class.equals(clazz); + } +} diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptContext.java b/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptContext.java new file mode 100644 index 00000000..68f6692d --- /dev/null +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptContext.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.scripts; + +import io.serverlessworkflow.api.types.RunTaskConfiguration; +import java.util.Map; + +public record ScriptContext( + Map args, + Map envs, + String code, + boolean isAwait, + RunTaskConfiguration.ProcessReturnType returnType) {} diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptLanguageId.java b/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptLanguageId.java new file mode 100644 index 00000000..70cf0fb6 --- /dev/null +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptLanguageId.java @@ -0,0 +1,47 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.scripts; + +import java.util.Arrays; + +public enum ScriptLanguageId { + JS("js"), + PYTHON("python"); + + private final String lang; + + ScriptLanguageId(String lang) { + this.lang = lang; + } + + public String getLang() { + return lang; + } + + public static ScriptLanguageId from(String lang) { + for (ScriptLanguageId l : ScriptLanguageId.values()) { + if (l.getLang().equalsIgnoreCase(lang)) { + return l; + } + } + throw new IllegalStateException( + "Unsupported script language: " + + lang + + ". Supported languages are: " + + Arrays.toString( + Arrays.stream(ScriptLanguageId.values()).map(ScriptLanguageId::getLang).toArray())); + } +} diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptRunner.java b/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptRunner.java new file mode 100644 index 00000000..f2795352 --- /dev/null +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/scripts/ScriptRunner.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.scripts; + +import io.serverlessworkflow.impl.ServicePriority; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import io.serverlessworkflow.impl.executors.RunScriptExecutor; + +/** Represents a script task that executes a script in a specific scripting language. */ +public interface ScriptRunner extends ServicePriority { + + /** + * The scripting language supported by this script task runner. + * + * @return the scripting language as {@link RunScriptExecutor.LanguageId} enum. + */ + ScriptLanguageId identifier(); + + WorkflowModel runScript( + ScriptContext script, + WorkflowContext workflowContext, + TaskContext taskContext, + WorkflowModel input); +} diff --git a/impl/core/src/main/resources/META-INF/services/io.serverlessworkflow.impl.executors.RunnableTask b/impl/core/src/main/resources/META-INF/services/io.serverlessworkflow.impl.executors.RunnableTask index 7d2be4f9..ea1bb37e 100644 --- a/impl/core/src/main/resources/META-INF/services/io.serverlessworkflow.impl.executors.RunnableTask +++ b/impl/core/src/main/resources/META-INF/services/io.serverlessworkflow.impl.executors.RunnableTask @@ -1,2 +1,3 @@ io.serverlessworkflow.impl.executors.RunWorkflowExecutor -io.serverlessworkflow.impl.executors.RunShellExecutor \ No newline at end of file +io.serverlessworkflow.impl.executors.RunShellExecutor +io.serverlessworkflow.impl.executors.RunScriptExecutor \ No newline at end of file diff --git a/impl/pom.xml b/impl/pom.xml index c59df5fa..49972c4b 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -16,6 +16,7 @@ 3.1.11 9.2.1 3.6.0 + 23.1.1 @@ -130,12 +131,17 @@ com.h2database h2-mvstore ${version.com.h2database} - - + + + io.serverlessworkflow + serverlessworkflow-impl-script-js + ${project.version} + + com.cronutils cron-utils ${version.com.cronutils} - + com.github.docker-java docker-java-core @@ -146,6 +152,17 @@ docker-java-transport-httpclient5 ${version.docker.java} + + org.graalvm.polyglot + js + ${version.org.graalvm.polyglot} + pom + + + org.graalvm.polyglot + polyglot + ${version.org.graalvm.polyglot} + @@ -163,5 +180,6 @@ validation container test + script-js diff --git a/impl/script-js/pom.xml b/impl/script-js/pom.xml new file mode 100644 index 00000000..1101de3f --- /dev/null +++ b/impl/script-js/pom.xml @@ -0,0 +1,25 @@ + + 4.0.0 + + io.serverlessworkflow + serverlessworkflow-impl + 8.0.0-SNAPSHOT + + serverlessworkflow-impl-script-js + Serverless Workflow :: Impl :: Script JavaScript + + + io.serverlessworkflow + serverlessworkflow-impl-core + + + org.graalvm.polyglot + polyglot + + + org.graalvm.polyglot + js + pom + + + \ No newline at end of file diff --git a/impl/script-js/src/main/java/io/serverlessworkflow/impl/executors/script/js/JavaScriptScriptTaskRunner.java b/impl/script-js/src/main/java/io/serverlessworkflow/impl/executors/script/js/JavaScriptScriptTaskRunner.java new file mode 100644 index 00000000..12540048 --- /dev/null +++ b/impl/script-js/src/main/java/io/serverlessworkflow/impl/executors/script/js/JavaScriptScriptTaskRunner.java @@ -0,0 +1,145 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.script.js; + +import io.serverlessworkflow.api.types.RunTaskConfiguration; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowError; +import io.serverlessworkflow.impl.WorkflowException; +import io.serverlessworkflow.impl.WorkflowModel; +import io.serverlessworkflow.impl.WorkflowModelFactory; +import io.serverlessworkflow.impl.executors.ProcessResult; +import io.serverlessworkflow.impl.scripts.ScriptContext; +import io.serverlessworkflow.impl.scripts.ScriptLanguageId; +import io.serverlessworkflow.impl.scripts.ScriptRunner; +import java.io.ByteArrayOutputStream; +import java.util.Map; +import java.util.function.Supplier; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.PolyglotException; +import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.Value; + +/** + * JavaScript implementation of the {@link ScriptRunner} interface that executes JavaScript scripts + * using GraalVM Polyglot API. + */ +public class JavaScriptScriptTaskRunner implements ScriptRunner { + + @Override + public ScriptLanguageId identifier() { + return ScriptLanguageId.JS; + } + + @Override + public WorkflowModel runScript( + ScriptContext script, + WorkflowContext workflowContext, + TaskContext taskContext, + WorkflowModel input) { + WorkflowApplication application = workflowContext.definition().application(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + + try (Context ctx = + Context.newBuilder() + .err(stderr) + .out(stdout) + .useSystemExit(true) + .allowCreateProcess(false) + .option("engine.WarnInterpreterOnly", "false") + .build()) { + + script + .args() + .forEach( + (key, val) -> { + ctx.getBindings(identifier().getLang()).putMember(key, val); + }); + + configureProcessEnv(ctx, script.envs()); + + if (!script.isAwait()) { + application + .executorService() + .submit( + () -> { + ctx.eval(identifier().getLang(), script.code()); + }); + return application.modelFactory().fromAny(input); + } + + ctx.eval(Source.create(identifier().getLang(), script.code())); + + return modelFromOutput( + script.returnType(), application.modelFactory(), stdout, () -> stderr.toString()); + } catch (PolyglotException e) { + if (e.getExitStatus() != 0 || e.isSyntaxError()) { + throw new WorkflowException(WorkflowError.runtime(taskContext, e).build()); + } else { + return modelFromOutput( + script.returnType(), application.modelFactory(), stdout, () -> buildStderr(e, stderr)); + } + } + } + + private WorkflowModel modelFromOutput( + RunTaskConfiguration.ProcessReturnType returnType, + WorkflowModelFactory modelFactory, + ByteArrayOutputStream stdout, + Supplier stderr) { + return switch (returnType) { + case ALL -> + modelFactory.fromAny(new ProcessResult(0, stdout.toString().trim(), stderr.get().trim())); + case NONE -> modelFactory.fromNull(); + case CODE -> modelFactory.from(0); + case STDOUT -> modelFactory.from(stdout.toString().trim()); + case STDERR -> modelFactory.from(stderr.get().trim()); + }; + } + + /* + * Gets the stderr message from the PolyglotException or the stderr stream. + * + * @param e the {@link PolyglotException} thrown during script execution + * @param stderr the stderr stream + * @return the stderr message + */ + private String buildStderr(PolyglotException e, ByteArrayOutputStream stderr) { + String err = stderr.toString(); + return err.isBlank() ? e.getMessage() : err.trim(); + } + + /* + * Configures the process.env object in the JavaScript context with the provided environment + * variables. + * + * @param context the GraalVM context + * @param envs the environment variables to set + */ + private void configureProcessEnv(Context context, Map envs) { + String js = ScriptLanguageId.JS.getLang(); + Value bindings = context.getBindings(js); + Value process = context.eval(js, "({ env: {} })"); + + for (var entry : envs.entrySet()) { + process.getMember("env").putMember(entry.getKey(), entry.getValue()); + } + bindings.putMember("process", process); + } +} diff --git a/impl/script-js/src/main/resources/META-INF/services/io.serverlessworkflow.impl.scripts.ScriptRunner b/impl/script-js/src/main/resources/META-INF/services/io.serverlessworkflow.impl.scripts.ScriptRunner new file mode 100644 index 00000000..0e3bb877 --- /dev/null +++ b/impl/script-js/src/main/resources/META-INF/services/io.serverlessworkflow.impl.scripts.ScriptRunner @@ -0,0 +1 @@ +io.serverlessworkflow.impl.executors.script.js.JavaScriptScriptTaskRunner \ No newline at end of file diff --git a/impl/test/pom.xml b/impl/test/pom.xml index f4e846cb..444ae5c1 100644 --- a/impl/test/pom.xml +++ b/impl/test/pom.xml @@ -33,6 +33,10 @@ io.serverlessworkflow serverlessworkflow-impl-jackson-jwt + + io.serverlessworkflow + serverlessworkflow-impl-script-js + org.glassfish.jersey.media jersey-media-json-jackson diff --git a/impl/test/src/test/java/io/serverlessworkflow/impl/test/RunScriptJavaScriptTest.java b/impl/test/src/test/java/io/serverlessworkflow/impl/test/RunScriptJavaScriptTest.java new file mode 100644 index 00000000..24832ebf --- /dev/null +++ b/impl/test/src/test/java/io/serverlessworkflow/impl/test/RunScriptJavaScriptTest.java @@ -0,0 +1,186 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.test; + +import io.serverlessworkflow.api.WorkflowReader; +import io.serverlessworkflow.api.types.Workflow; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowModel; +import io.serverlessworkflow.impl.executors.ProcessResult; +import java.io.IOException; +import java.util.Map; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.assertj.core.api.Assertions; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class RunScriptJavaScriptTest { + + private MockWebServer fileServer; + + @BeforeEach + void setUp() throws IOException { + fileServer = new MockWebServer(); + fileServer.start(8886); + } + + @AfterEach + void tearDown() throws IOException { + fileServer.shutdown(); + } + + @Test + void testConsoleLog() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath("workflows-samples/run-script/console-log.yaml"); + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + WorkflowModel model = appl.workflowDefinition(workflow).instance(Map.of()).start().join(); + + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(model.asText()).isPresent(); + softly.assertThat(model.asText().get()).isEqualTo("hello from script"); + }); + } + } + + @Test + void testConsoleLogWithArgs() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath( + "workflows-samples/run-script/console-log-args.yaml"); + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + WorkflowModel model = appl.workflowDefinition(workflow).instance(Map.of()).start().join(); + + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(model.asText()).isPresent(); + softly.assertThat(model.asText().get()).isEqualTo("Hello, world!"); + }); + } + } + + @Test + void testConsoleLogWithEnvs() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath( + "workflows-samples/run-script/console-log-envs.yaml"); + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + WorkflowModel model = appl.workflowDefinition(workflow).instance(Map.of()).start().join(); + + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(model.asText()).isPresent(); + softly + .assertThat(model.asText().get()) + .isEqualTo("Running JavaScript code using Serverless Workflow!"); + }); + } + } + + @Test + void testConsoleLogWithExternalSource() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath( + "workflows-samples/run-script/console-log-external-source.yaml"); + + fileServer.enqueue( + new MockResponse() + .setBody( + """ + console.log("hello from script"); + """) + .setHeader("Content-Type", "application/javascript") + .setResponseCode(200)); + + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + WorkflowModel model = appl.workflowDefinition(workflow).instance(Map.of()).start().join(); + + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(model.asText()).isPresent(); + softly.assertThat(model.asText().get()).isEqualTo("hello from script"); + }); + } + } + + @Test + void testFunctionThrowingError() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath( + "workflows-samples/run-script/function-with-throw.yaml"); + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + WorkflowModel model = appl.workflowDefinition(workflow).instance(Map.of()).start().join(); + + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(model.asText()).isPresent(); + softly.assertThat(model.asText().get()).isEqualTo("Error: This is a test error"); + }); + } + } + + @Test + void testFunctionThrowingErrorAndReturnAll() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath( + "workflows-samples/run-script/function-with-throw-all.yaml"); + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + WorkflowModel model = appl.workflowDefinition(workflow).instance(Map.of()).start().join(); + + SoftAssertions.assertSoftly( + softly -> { + ProcessResult r = model.as(ProcessResult.class).orElseThrow(); + softly.assertThat(r.stderr()).isEqualTo("Error: This is a test error"); + softly.assertThat(r.stdout()).isEqualTo("logged before the 'throw' statement"); + softly.assertThat(r.code()).isEqualTo(0); + }); + } + } + + @Test + void testFunctionWithSyntaxError() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath( + "workflows-samples/run-script/function-with-syntax-error.yaml"); + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + Assertions.assertThatThrownBy( + () -> { + appl.workflowDefinition(workflow).instance(Map.of()).start().join(); + }) + .hasMessageContaining("SyntaxError"); + } + } + + @Test + void testConsoleLogNotAwaiting() throws IOException { + Workflow workflow = + WorkflowReader.readWorkflowFromClasspath( + "workflows-samples/run-script/console-log-not-awaiting.yaml"); + try (WorkflowApplication appl = WorkflowApplication.builder().build()) { + Map input = Map.of("hello", "world"); + + WorkflowModel model = appl.workflowDefinition(workflow).instance(input).start().join(); + + Map output = model.asMap().orElseThrow(); + + Assertions.assertThat(output).isEqualTo(input); + } + } +} diff --git a/impl/test/src/test/resources/workflows-samples/run-script/console-log-args.yaml b/impl/test/src/test/resources/workflows-samples/run-script/console-log-args.yaml new file mode 100644 index 00000000..c51681ea --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/console-log-args.yaml @@ -0,0 +1,14 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + arguments: + greetings: Hello, world! + code: > + console.log(greetings) \ No newline at end of file diff --git a/impl/test/src/test/resources/workflows-samples/run-script/console-log-envs.yaml b/impl/test/src/test/resources/workflows-samples/run-script/console-log-envs.yaml new file mode 100644 index 00000000..36684b2b --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/console-log-envs.yaml @@ -0,0 +1,14 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + code: > + console.log(`Running ${process.env.LANGUAGE} code using Serverless Workflow!`); + environment: + LANGUAGE: JavaScript \ No newline at end of file diff --git a/impl/test/src/test/resources/workflows-samples/run-script/console-log-external-source.yaml b/impl/test/src/test/resources/workflows-samples/run-script/console-log-external-source.yaml new file mode 100644 index 00000000..5ab9ba4d --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/console-log-external-source.yaml @@ -0,0 +1,13 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + source: + endpoint: + uri: http://localhost:8886/script.js diff --git a/impl/test/src/test/resources/workflows-samples/run-script/console-log-not-awaiting.yaml b/impl/test/src/test/resources/workflows-samples/run-script/console-log-not-awaiting.yaml new file mode 100644 index 00000000..c67adb64 --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/console-log-not-awaiting.yaml @@ -0,0 +1,13 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + code: > + console.log("hello from script"); + await: false diff --git a/impl/test/src/test/resources/workflows-samples/run-script/console-log.yaml b/impl/test/src/test/resources/workflows-samples/run-script/console-log.yaml new file mode 100644 index 00000000..79c5013a --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/console-log.yaml @@ -0,0 +1,12 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + code: > + console.log("hello from script"); diff --git a/impl/test/src/test/resources/workflows-samples/run-script/function-with-syntax-error.yaml b/impl/test/src/test/resources/workflows-samples/run-script/function-with-syntax-error.yaml new file mode 100644 index 00000000..75bd074d --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/function-with-syntax-error.yaml @@ -0,0 +1,19 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + code: > + // there is no reserved word func in JavaScript, it should be function + func hello() { + console.log("hello from script"); + throw new Error("This is a test error"); + } + + hello(); + return: stderr diff --git a/impl/test/src/test/resources/workflows-samples/run-script/function-with-throw-all.yaml b/impl/test/src/test/resources/workflows-samples/run-script/function-with-throw-all.yaml new file mode 100644 index 00000000..c6e6cf3f --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/function-with-throw-all.yaml @@ -0,0 +1,18 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + code: > + function hello() { + console.log("logged before the 'throw' statement"); + throw new Error("This is a test error"); + } + + hello(); + return: all diff --git a/impl/test/src/test/resources/workflows-samples/run-script/function-with-throw.yaml b/impl/test/src/test/resources/workflows-samples/run-script/function-with-throw.yaml new file mode 100644 index 00000000..89236129 --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/function-with-throw.yaml @@ -0,0 +1,18 @@ +document: + dsl: '1.0.2' + namespace: test + name: run-script-example + version: '0.1.0' +do: + - runScript: + run: + script: + language: js + code: > + function hello() { + console.log("hello from script"); + throw new Error("This is a test error"); + } + + hello(); + return: stderr diff --git a/impl/test/src/test/resources/workflows-samples/run-script/script.js b/impl/test/src/test/resources/workflows-samples/run-script/script.js new file mode 100644 index 00000000..f7b8bd8c --- /dev/null +++ b/impl/test/src/test/resources/workflows-samples/run-script/script.js @@ -0,0 +1 @@ +console.log("hello from script"); \ No newline at end of file