diff --git a/.gitignore b/.gitignore index 1dfd7048..4d08f121 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,7 @@ target/ build/ ### VS Code ### -.vscode/ \ No newline at end of file +.vscode/ + +# Bob-Shell +.bob/notes/ \ No newline at end of file diff --git a/experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java b/experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java index a11d2c75..a6520977 100644 --- a/experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java +++ b/experimental/fluent/func/src/test/java/io/serverlessworkflow/fluent/func/FuncDSLTest.java @@ -266,7 +266,13 @@ void get_named_with_authentication_uses_auth_policy() { assertEquals("GET", http.getWith().getMethod()); assertEquals( "http://service/api/users", - http.getWith().getEndpoint().getUriTemplate().getLiteralUri().toString(), + http.getWith() + .getEndpoint() + .getEndpointConfiguration() + .getUri() + .getLiteralEndpointURI() + .getLiteralUri() + .toString(), "endpoint should be set from get(name, endpoint, auth)"); assertNotNull( @@ -371,7 +377,13 @@ void post_named_with_authentication() { assertEquals("POST", http.getWith().getMethod()); assertEquals( "https://orders.example.com/api/orders", - http.getWith().getEndpoint().getUriTemplate().getLiteralUri().toString()); + http.getWith() + .getEndpoint() + .getEndpointConfiguration() + .getUri() + .getLiteralEndpointURI() + .getLiteralUri() + .toString()); assertEquals(body, http.getWith().getBody()); assertNotNull(http.getWith().getEndpoint().getEndpointConfiguration().getAuthentication()); @@ -409,7 +421,13 @@ void call_with_preconfigured_http_spec() { assertEquals("POST", http.getWith().getMethod()); assertEquals( "http://service/api", - http.getWith().getEndpoint().getUriTemplate().getLiteralUri().toString()); + http.getWith() + .getEndpoint() + .getEndpointConfiguration() + .getUri() + .getLiteralEndpointURI() + .getLiteralUri() + .toString()); assertEquals( "svc-auth", http.getWith() diff --git a/experimental/test/pom.xml b/experimental/test/pom.xml index 5661f582..6cf53a5c 100644 --- a/experimental/test/pom.xml +++ b/experimental/test/pom.xml @@ -71,6 +71,13 @@ io.serverlessworkflow serverlessworkflow-impl-jq + test + + + io.serverlessworkflow + serverlessworkflow-impl-openapi + ${project.version} + test org.glassfish.jersey.media diff --git a/experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncOpenAPITest.java b/experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncOpenAPITest.java new file mode 100644 index 00000000..dbcdd207 --- /dev/null +++ b/experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncOpenAPITest.java @@ -0,0 +1,112 @@ +/* + * 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.fluent.test; + +import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.openapi; + +import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowDefinition; +import io.serverlessworkflow.impl.WorkflowInstance; +import io.serverlessworkflow.impl.WorkflowModel; +import java.io.IOException; +import java.net.URI; +import java.util.Map; +import mockwebserver3.MockResponse; +import mockwebserver3.MockWebServer; +import okhttp3.Headers; +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 FuncOpenAPITest { + + private static MockWebServer mockWebServer; + + @BeforeEach + public void setup() throws IOException { + mockWebServer = new MockWebServer(); + mockWebServer.start(0); + } + + @AfterEach + public void tearDown() { + mockWebServer.close(); + } + + @Test + void test_openapi_document_with_non_jq_uri_string() { + String mockedSwaggerDoc = + """ + { + "swagger": "2.0", + "info": { "version": "1.0.0", "title": "Mock Petstore" }, + "host": "localhost:%d", + "basePath": "/v2", + "schemes": [ "http" ], + "paths": { + "/pet/findByStatus": { + "get": { + "operationId": "findPetsByStatus", + "parameters": [ + { + "name": "status", + "in": "query", + "required": true, + "type": "string" + } + ], + "responses": { "200": { "description": "OK" } } + } + } + } + } + """ + .formatted(mockWebServer.getPort()); + + mockWebServer.enqueue( + new MockResponse(200, Headers.of("Content-Type", "application/json"), mockedSwaggerDoc)); + mockWebServer.enqueue( + new MockResponse( + 200, + Headers.of("Content-Type", "application/json"), + """ + { "description": "OK" } + """)); + var w = + FuncWorkflowBuilder.workflow("openapi-call-workflow") + .tasks( + openapi() + .document(URI.create(mockWebServer.url("/v2/swagger.json").toString())) + .operation("findPetsByStatus") + .parameters(Map.of("status", "available"))) + .build(); + + try (WorkflowApplication app = WorkflowApplication.builder().build()) { + + WorkflowDefinition def = app.workflowDefinition(w); + WorkflowInstance instance = def.instance(Map.of()); + WorkflowModel model = instance.start().join(); + + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(model).isNotNull(); + softly.assertThat(model.asMap()).contains(Map.of("description", "OK")); + }); + } + } +} diff --git a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/spi/CallHttpTaskFluent.java b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/spi/CallHttpTaskFluent.java index 61cf0db6..89ca52fd 100644 --- a/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/spi/CallHttpTaskFluent.java +++ b/fluent/spec/src/main/java/io/serverlessworkflow/fluent/spec/spi/CallHttpTaskFluent.java @@ -84,23 +84,21 @@ default SELF endpoint(String expr, Consumer= 0 || trimmed.indexOf('}') >= 0) { - template.setLiteralUriTemplate(trimmed); - } else { - template.setLiteralUri(URI.create(trimmed)); - } - endpoint.setUriTemplate(template); - return endpoint; - } - // Let the runtime engine to verify if it's a valid jq expression since ${} it's not the only - // way of checking it. - endpoint.setRuntimeExpression(expr); + if (auth != null) { + endpoint.setEndpointConfiguration( + new EndpointConfiguration(buildEndpointUri(trimmed)).withAuthentication(auth)); + } else if (isUrlLike(trimmed)) { + endpoint.setUriTemplate(buildUriTemplate(trimmed)); + } else { + // Let the runtime engine to verify if it's a valid jq expression since ${} it's not the only + // way of checking it. + endpoint.setRuntimeExpression(uri); + } return endpoint; } + private static EndpointUri buildEndpointUri(String uri) { + EndpointUri endpointUri = new EndpointUri(); + if (isUrlLike(uri)) { + endpointUri.setLiteralEndpointURI(buildUriTemplate(uri)); + } else { + endpointUri.setExpressionEndpointURI(uri); + } + return endpointUri; + } + + private static UriTemplate buildUriTemplate(String trimmed) { + UriTemplate template = new UriTemplate(); + if (trimmed.indexOf('{') >= 0 || trimmed.indexOf('}') >= 0) { + template.setLiteralUriTemplate(trimmed); + } else { + template.setLiteralUri(URI.create(trimmed)); + } + return template; + } + private static boolean isUrlLike(String value) { // same idea as UriTemplate.literalUriTemplate_Pattern: ^[A-Za-z][A-Za-z0-9+\\-.]*://.* int idx = value.indexOf("://"); diff --git a/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallHttpAuthDslTest.java b/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallHttpAuthDslTest.java index 874cce3b..94fedc45 100644 --- a/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallHttpAuthDslTest.java +++ b/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallHttpAuthDslTest.java @@ -47,7 +47,8 @@ void when_call_http_with_basic_auth_on_endpoint_expr() { assertThat(wf.getDo().get(0).getTask().getCallTask().get()).isNotNull(); // Endpoint expression is set - assertThat(args.getEndpoint().getRuntimeExpression()).isEqualTo(EXPR_ENDPOINT); + assertThat(args.getEndpoint().getEndpointConfiguration().getUri().getExpressionEndpointURI()) + .isEqualTo(EXPR_ENDPOINT); // Auth populated: BASIC (others null) var auth = @@ -83,7 +84,8 @@ void when_call_http_with_bearer_auth_on_endpoint_expr() { var args = wf.getDo().get(0).getTask().getCallTask().getCallHTTP().getWith(); - assertThat(args.getEndpoint().getRuntimeExpression()).isEqualTo(EXPR_ENDPOINT); + assertThat(args.getEndpoint().getEndpointConfiguration().getUri().getExpressionEndpointURI()) + .isEqualTo(EXPR_ENDPOINT); var auth = args.getEndpoint().getEndpointConfiguration().getAuthentication().getAuthenticationPolicy(); @@ -112,7 +114,8 @@ void when_call_http_with_digest_auth_on_endpoint_expr() { var args = wf.getDo().get(0).getTask().getCallTask().getCallHTTP().getWith(); - assertThat(args.getEndpoint().getRuntimeExpression()).isEqualTo(EXPR_ENDPOINT); + assertThat(args.getEndpoint().getEndpointConfiguration().getUri().getExpressionEndpointURI()) + .isEqualTo(EXPR_ENDPOINT); var auth = args.getEndpoint().getEndpointConfiguration().getAuthentication().getAuthenticationPolicy(); @@ -158,7 +161,8 @@ void when_call_http_with_oidc_auth_on_endpoint_expr_with_client() { var args = wf.getDo().get(0).getTask().getCallTask().getCallHTTP().getWith(); - assertThat(args.getEndpoint().getRuntimeExpression()).isEqualTo(EXPR_ENDPOINT); + assertThat(args.getEndpoint().getEndpointConfiguration().getUri().getExpressionEndpointURI()) + .isEqualTo(EXPR_ENDPOINT); var auth = args.getEndpoint().getEndpointConfiguration().getAuthentication().getAuthenticationPolicy(); @@ -203,7 +207,8 @@ void when_call_http_with_oauth2_alias_on_endpoint_expr_without_client() { var args = wf.getDo().get(0).getTask().getCallTask().getCallHTTP().getWith(); - assertThat(args.getEndpoint().getRuntimeExpression()).isEqualTo(EXPR_ENDPOINT); + assertThat(args.getEndpoint().getEndpointConfiguration().getUri().getExpressionEndpointURI()) + .isEqualTo(EXPR_ENDPOINT); var auth = args.getEndpoint().getEndpointConfiguration().getAuthentication().getAuthenticationPolicy(); diff --git a/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallOpenApiDslTest.java b/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallOpenApiDslTest.java index 70a91f28..fc2cc4b6 100644 --- a/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallOpenApiDslTest.java +++ b/fluent/spec/src/test/java/io/serverlessworkflow/fluent/spec/dsl/CallOpenApiDslTest.java @@ -55,7 +55,13 @@ void when_call_openapi_with_basic_auth_on_document_expr() { // Document and endpoint expression assertThat(with.getDocument()).isNotNull(); assertThat(with.getDocument().getEndpoint()).isNotNull(); - assertThat(with.getDocument().getEndpoint().getRuntimeExpression()).isEqualTo(EXPR_DOCUMENT); + assertThat( + with.getDocument() + .getEndpoint() + .getEndpointConfiguration() + .getUri() + .getExpressionEndpointURI()) + .isEqualTo(EXPR_DOCUMENT); // Endpoint configuration URI expression var endpointConfig = with.getDocument().getEndpoint().getEndpointConfiguration();