Skip to content

Commit f758232

Browse files
committed
Add tests for redirect
Signed-off-by: Matheus Cruz <matheuscruz.dev@gmail.com>
1 parent c4cf709 commit f758232

16 files changed

+297
-24
lines changed

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AbstractHttpExecutorBuilder.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ protected static RequestSupplier buildRequestSupplier(
4646
return new WithoutBodyRequestSupplier(Invocation.Builder::head, application, redirect);
4747
case HttpMethod.OPTIONS:
4848
return new WithoutBodyRequestSupplier(Invocation.Builder::options, application, redirect);
49-
case HttpMethod.PATCH:
50-
return new WithBodyRequestSupplier(
51-
(request, entity) -> request.method("patch", entity), application, body, redirect);
5249
case HttpMethod.GET:
5350
default:
5451
return new WithoutBodyRequestSupplier(Invocation.Builder::get, application, redirect);

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AbstractRequestSupplier.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package io.serverlessworkflow.impl.executors.http;
1717

18+
import static jakarta.ws.rs.core.Response.Status.Family.REDIRECTION;
19+
import static jakarta.ws.rs.core.Response.Status.Family.SUCCESSFUL;
20+
1821
import io.serverlessworkflow.impl.TaskContext;
1922
import io.serverlessworkflow.impl.WorkflowContext;
2023
import io.serverlessworkflow.impl.WorkflowError;
@@ -36,20 +39,39 @@ public AbstractRequestSupplier(boolean redirect) {
3639
public WorkflowModel apply(
3740
Builder request, WorkflowContext workflow, TaskContext task, WorkflowModel model) {
3841
HttpModelConverter converter = HttpConverterResolver.converter(workflow, task);
42+
43+
if (!redirect) {
44+
// disable automatic redirects handling from Jersey client
45+
request.property("jersey.config.client.followRedirects", false);
46+
}
47+
3948
Response response = invokeRequest(request, converter, workflow, task, model);
40-
validateStatus(task, response, converter);
49+
validateStatus(task, response);
4150
return workflow
4251
.definition()
4352
.application()
4453
.modelFactory()
4554
.fromAny(response.readEntity(converter.responseType()));
4655
}
4756

48-
private void validateStatus(TaskContext task, Response response, HttpModelConverter converter) {
49-
if (response.getStatusInfo().getFamily() != Family.SUCCESSFUL) {
57+
private void validateStatus(TaskContext task, Response response) {
58+
Family statusFamily = response.getStatusInfo().getFamily();
59+
boolean isSuccess = statusFamily.equals(SUCCESSFUL);
60+
boolean isRedirect = statusFamily.equals(REDIRECTION);
61+
boolean valid = redirect ? (isSuccess || isRedirect) : isSuccess;
62+
63+
if (!valid) {
64+
String expectedRange = redirect ? "200-399" : "200-299";
5065
throw new WorkflowException(
51-
converter
52-
.errorFromResponse(WorkflowError.communication(response.getStatus(), task), response)
66+
WorkflowError.communication(
67+
response.getStatus(),
68+
task,
69+
String.format(
70+
"The property 'redirect' is set to %s but received status %d (%s); expected status in the %s range",
71+
redirect,
72+
response.getStatus(),
73+
response.getStatusInfo().getReasonPhrase(),
74+
expectedRange))
5375
.build());
5476
}
5577
}

impl/test/src/test/java/io/serverlessworkflow/impl/test/HTTPWorkflowDefinitionTest.java

Lines changed: 169 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,23 @@
1818
import static io.serverlessworkflow.api.WorkflowReader.readWorkflowFromClasspath;
1919
import static org.assertj.core.api.Assertions.assertThat;
2020
import static org.assertj.core.api.Assertions.catchThrowableOfType;
21+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
2122

2223
import io.serverlessworkflow.impl.WorkflowApplication;
2324
import io.serverlessworkflow.impl.WorkflowModel;
2425
import java.io.IOException;
2526
import java.util.Map;
27+
import java.util.concurrent.CompletionException;
2628
import java.util.stream.Stream;
29+
import mockwebserver3.MockResponse;
30+
import mockwebserver3.MockWebServer;
31+
import okhttp3.Headers;
2732
import org.assertj.core.api.Condition;
2833
import org.junit.jupiter.api.AfterAll;
34+
import org.junit.jupiter.api.AfterEach;
2935
import org.junit.jupiter.api.BeforeAll;
36+
import org.junit.jupiter.api.BeforeEach;
37+
import org.junit.jupiter.api.Test;
3038
import org.junit.jupiter.params.ParameterizedTest;
3139
import org.junit.jupiter.params.provider.Arguments;
3240
import org.junit.jupiter.params.provider.MethodSource;
@@ -36,6 +44,8 @@ public class HTTPWorkflowDefinitionTest {
3644

3745
private static WorkflowApplication appl;
3846

47+
private static MockWebServer mockServer;
48+
3949
@BeforeAll
4050
static void init() {
4151
appl = WorkflowApplication.builder().build();
@@ -46,10 +56,23 @@ static void cleanup() {
4656
appl.close();
4757
}
4858

59+
@BeforeEach
60+
void setup() throws IOException {
61+
mockServer = new MockWebServer();
62+
mockServer.start(9876);
63+
}
64+
65+
@AfterEach
66+
void shutdownServer() {
67+
mockServer.close();
68+
}
69+
4970
@ParameterizedTest
5071
@MethodSource("provideParameters")
51-
void testWorkflowExecution(String fileName, Object input, Condition<Object> condition)
72+
void testWorkflowExecution(
73+
String fileName, Object input, Runnable setup, Condition<Object> condition)
5274
throws IOException {
75+
setup.run();
5376
assertThat(
5477
appl.workflowDefinition(readWorkflowFromClasspath(fileName))
5578
.instance(input)
@@ -94,27 +117,165 @@ private static Stream<Arguments> provideParameters() {
94117
Condition<WorkflowModel> postCondition =
95118
new Condition<WorkflowModel>(
96119
o -> o.asText().orElseThrow().equals("Javierito"), "CallHttpPostCondition");
120+
121+
Condition<WorkflowModel> putCondition =
122+
new Condition<>(o -> o.asText().get().contains("John"), "CallHttpPutCondition");
123+
124+
Condition<WorkflowModel> patchCondition =
125+
new Condition<>(o -> o.asText().get().contains("John"), "CallHttpPatchCondition");
126+
97127
Map<String, String> postMap = Map.of("name", "Javierito", "surname", "Unknown");
128+
Map<String, Object> putMap = Map.of("firstName", "John");
129+
130+
Runnable setupPost =
131+
() ->
132+
mockServer.enqueue(
133+
new MockResponse(
134+
200,
135+
Headers.of("Content-Type", "application/json"),
136+
"""
137+
{
138+
"firstName": "Javierito"
139+
}
140+
"""));
141+
98142
return Stream.of(
99-
Arguments.of("workflows-samples/callGetHttp.yaml", petInput, petCondition),
143+
Arguments.of("workflows-samples/call-http-get.yaml", petInput, doNothing, petCondition),
100144
Arguments.of(
101-
"workflows-samples/callGetHttp.yaml",
145+
"workflows-samples/call-http-get.yaml",
102146
Map.of("petId", "-1"),
147+
doNothing,
103148
new Condition<WorkflowModel>(
104149
o -> o.asMap().orElseThrow().containsKey("petId"), "notFoundCondition")),
105150
Arguments.of(
106-
"workflows-samples/call-http-endpoint-interpolation.yaml", petInput, petCondition),
151+
"workflows-samples/call-http-endpoint-interpolation.yaml",
152+
petInput,
153+
doNothing,
154+
petCondition),
107155
Arguments.of(
108-
"workflows-samples/call-http-query-parameters.yaml", starTrekInput, starTrekCondition),
156+
"workflows-samples/call-http-query-parameters.yaml",
157+
starTrekInput,
158+
doNothing,
159+
starTrekCondition),
109160
Arguments.of(
110-
"workflows-samples/callFindByStatusHttp.yaml",
161+
"workflows-samples/call-http-find-by-status.yaml",
111162
Map.of(),
163+
doNothing,
112164
new Condition<WorkflowModel>(o -> !o.asCollection().isEmpty(), "HasElementCondition")),
113165
Arguments.of(
114166
"workflows-samples/call-http-query-parameters-external-schema.yaml",
115167
starTrekInput,
168+
doNothing,
116169
starTrekCondition),
117-
Arguments.of("workflows-samples/callPostHttp.yaml", postMap, postCondition),
118-
Arguments.of("workflows-samples/callPostHttpAsExpr.yaml", postMap, postCondition));
170+
Arguments.of("workflows-samples/call-http-post.yaml", postMap, setupPost, postCondition),
171+
Arguments.of(
172+
"workflows-samples/call-http-delete.yaml",
173+
Map.of(),
174+
doNothing,
175+
new Condition<WorkflowModel>(o -> o.asMap().isEmpty(), "HTTP delete")),
176+
Arguments.of("workflows-samples/call-http-put.yaml", putMap, doNothing, putCondition));
119177
}
178+
179+
private static final Runnable doNothing = () -> {};
180+
181+
@Test
182+
void post_should_run_call_http_with_expression_body() {
183+
mockServer.enqueue(
184+
new MockResponse(
185+
200,
186+
Headers.of("Content-Type", "application/json"),
187+
"""
188+
{
189+
"firstName": "Javierito"
190+
}
191+
"""));
192+
193+
assertDoesNotThrow(
194+
() -> {
195+
appl.workflowDefinition(
196+
readWorkflowFromClasspath("workflows-samples/call-http-post-expr.yaml"))
197+
.instance(Map.of("name", "Javierito", "surname", "Unknown"))
198+
.start()
199+
.join();
200+
});
201+
}
202+
203+
@Test
204+
void testHeadCall() {
205+
mockServer.enqueue(
206+
new MockResponse(
207+
200,
208+
Headers.of(
209+
Map.of(
210+
"Content-Length",
211+
"123",
212+
"Content-Type",
213+
"application/json",
214+
"X-Custom-Header",
215+
"CustomValue")),
216+
""));
217+
assertDoesNotThrow(
218+
() -> {
219+
appl.workflowDefinition(
220+
readWorkflowFromClasspath("workflows-samples/call-http-head.yaml"))
221+
.instance(Map.of())
222+
.start()
223+
.join();
224+
});
225+
}
226+
227+
@Test
228+
void testOptionsCall() {
229+
mockServer.enqueue(new MockResponse(200, Headers.of("Allow", "GET, POST, OPTIONS"), ""));
230+
231+
assertDoesNotThrow(
232+
() -> {
233+
appl.workflowDefinition(
234+
readWorkflowFromClasspath("workflows-samples/call-http-options.yaml"))
235+
.instance(Map.of())
236+
.start()
237+
.join();
238+
});
239+
}
240+
241+
@Test
242+
void testRedirectAsFalse() {
243+
mockServer.enqueue(
244+
new MockResponse(301, Headers.of("Location", "http://localhost:9876/redirected"), ""));
245+
246+
CompletionException exception =
247+
catchThrowableOfType(
248+
CompletionException.class,
249+
() ->
250+
appl.workflowDefinition(
251+
readWorkflowFromClasspath(
252+
"workflows-samples/call-http-redirect-false.yaml"))
253+
.instance(Map.of())
254+
.start()
255+
.join());
256+
257+
assertThat(exception.getCause().getMessage())
258+
.contains(
259+
"The property 'redirect' is set to false but received status 301 (Redirection); expected status in the 200-299 range");
260+
}
261+
262+
// @Test
263+
// void testRedirectAsTrueWhenReceivingRedirection() {
264+
// mockServer.enqueue(
265+
// new MockResponse(301, Headers.of("Location", "http://localhost:9876/redirected"), ""));
266+
//
267+
// mockServer.enqueue(
268+
// new MockResponse(
269+
// 200, Headers.of("Content-Type", "application/json"), "{\"status\":\"OK\"}"));
270+
//
271+
// assertDoesNotThrow(
272+
// () -> {
273+
// appl.workflowDefinition(
274+
//
275+
// readWorkflowFromClasspath("workflows-samples/call-with-response-output-expr.yaml"))
276+
// .instance(Map.of())
277+
// .start()
278+
// .join();
279+
// });
280+
// }
120281
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
document:
2+
dsl: 1.0.0-alpha1
3+
namespace: test
4+
name: call-http-delete
5+
version: 1.0.0
6+
do:
7+
- deleteAuthor:
8+
call: http
9+
with:
10+
method: delete
11+
endpoint:
12+
uri: https://fakerestapi.azurewebsites.net/api/v1/Authors/1

impl/test/src/test/resources/workflows-samples/callFindByStatusHttp.yaml renamed to impl/test/src/test/resources/workflows-samples/call-http-find-by-status.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
document:
22
dsl: 1.0.0-alpha1
33
namespace: test
4-
name: http-call-find-by-status
4+
name: call-http-find-by-status
55
version: 1.0.0
66
do:
77
- tryGetPet:

impl/test/src/test/resources/workflows-samples/callGetHttp.yaml renamed to impl/test/src/test/resources/workflows-samples/call-http-get.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
document:
22
dsl: 1.0.0-alpha1
33
namespace: test
4-
name: http-call-with-response
4+
name: call-http-with-response
55
version: 1.0.0
66
do:
77
- tryGetPet:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
document:
2+
dsl: 1.0.0-alpha1
3+
namespace: test
4+
name: call-http-head
5+
version: 1.0.0
6+
do:
7+
- useHead:
8+
call: http
9+
with:
10+
method: head
11+
endpoint:
12+
uri: http://localhost:9876/users/1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
document:
2+
dsl: 1.0.0-alpha1
3+
namespace: test
4+
name: call-http-options
5+
version: 1.0.0
6+
do:
7+
- useOptions:
8+
call: http
9+
with:
10+
method: options
11+
endpoint:
12+
uri: http://localhost:9876/users/1
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
document:
22
dsl: 1.0.0-alpha1
33
namespace: test
4-
name: http-call-with-response-output-expr
4+
name: cal-http-with-body-and-response-with-expr
55
version: 1.0.0
66
do:
7-
- postPet:
7+
- postUsers:
88
call: http
99
with:
10+
redirect: false
1011
method: post
1112
endpoint:
12-
uri: https://fakerestapi.azurewebsites.net/api/v1/Authors
13+
uri: http://localhost:9876/users
1314
body: "${{firstName: .name, lastName:.surname}}"
1415
output:
1516
as: .firstName

impl/test/src/test/resources/workflows-samples/callPostHttp.yaml renamed to impl/test/src/test/resources/workflows-samples/call-http-post.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
document:
22
dsl: 1.0.0-alpha1
33
namespace: test
4-
name: http-call-with-response-output
4+
name: call-http-with-response-output
55
version: 1.0.0
66
do:
7-
- postPet:
7+
- postAuthors:
88
call: http
99
with:
1010
method: post

0 commit comments

Comments
 (0)