From 3392c2d7c37e06f6fd73fe2727631df21eb8ce0e Mon Sep 17 00:00:00 2001 From: KiKoS0 <22998716+KiKoS0@users.noreply.github.com> Date: Wed, 28 Feb 2024 08:39:22 +0100 Subject: [PATCH] Fix serialization of Java objects in step results/errors (#41) Step/Function result classes are no longer required to be public with strictly public properties to serialize correctly when sending response payloads to Inngest. --- .../src/main/kotlin/com/inngest/Comm.kt | 14 +++++-- .../springbootdemo/DevServerComponent.java | 23 ++++++++-- .../com/inngest/springbootdemo/Result.java | 16 ++++--- .../CustomStepResultIntegrationTest.java | 42 +++++++++++++++++++ .../springbootdemo/DemoTestConfiguration.java | 1 + .../InngestFunctionTestHelpers.java | 23 ++++++++++ .../SleepFunctionIntegrationTest.java | 2 +- .../WaitForEventFunctionIntegrationTest.java | 4 +- 8 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/CustomStepResultIntegrationTest.java diff --git a/inngest-core/src/main/kotlin/com/inngest/Comm.kt b/inngest-core/src/main/kotlin/com/inngest/Comm.kt index b9bd78e4..611bc291 100644 --- a/inngest-core/src/main/kotlin/com/inngest/Comm.kt +++ b/inngest-core/src/main/kotlin/com/inngest/Comm.kt @@ -3,6 +3,7 @@ package com.inngest import com.beust.klaxon.Json import com.beust.klaxon.Klaxon import com.inngest.signingkey.getAuthorizationHeader +import com.fasterxml.jackson.databind.ObjectMapper import java.io.IOException data class ExecutionRequestPayload( @@ -83,7 +84,7 @@ class CommHandler( body = result.data } return CommResponse( - body = Klaxon().toJsonString(body), + body = parseRequestBody(body), statusCode = result.statusCode, headers = headers, ) @@ -98,13 +99,18 @@ class CommHandler( stack = e.stackTrace.joinToString(separator = "\n"), ) return CommResponse( - body = Klaxon().toJsonString(err), + body = parseRequestBody(err), statusCode = statusCode, headers = headers.plus(retryDecision.headers), ) } } + private fun parseRequestBody(requestBody: Any?): String { + val mapper = ObjectMapper() + return mapper.writeValueAsString(requestBody) + } + private fun getFunctionConfigs(): List { val configs: MutableList = mutableListOf() functions.forEach { entry -> configs.add(entry.value.getFunctionConfig(getServeUrl())) } @@ -133,7 +139,7 @@ class CommHandler( // TODO - Add headers to output val body: Map = mapOf() - return Klaxon().toJsonString(body) + return parseRequestBody(body) } fun sync(): Result { @@ -142,7 +148,7 @@ class CommHandler( fun introspect(): String { val requestPayload = getRegistrationRequestPayload() - return Klaxon().toJsonString(requestPayload) + return parseRequestBody(requestPayload) } private fun getRegistrationRequestPayload(): RegistrationRequestPayload { diff --git a/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/DevServerComponent.java b/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/DevServerComponent.java index c9586bef..f4c2b700 100644 --- a/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/DevServerComponent.java +++ b/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/DevServerComponent.java @@ -1,6 +1,7 @@ package com.inngest.springbootdemo; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.Request; @@ -52,12 +53,28 @@ EventRunsResponse runsByEvent(String eventId) throws Exception { }); } - RunResponse runById(String eventId) throws Exception { + RunResponse runById(String eventId, Class outputType) throws Exception { Request request = new Request.Builder() .url(String.format("%s/v1/runs/%S", baseUrl, eventId)) .build(); - return makeRequest(request, new TypeReference>() { - }); + try (Response response = httpClient.newCall(request).execute()) { + if (response.code() == 200) { + assert response.body() != null; + + String strResponse = response.body().string(); + ObjectMapper mapper = new ObjectMapper(); + + JsonNode node = mapper.readTree(strResponse); + JsonNode dataResult = node.path("data").path("output"); + + T output = mapper.treeToValue(dataResult, outputType); + RunResponse result = mapper.readValue(strResponse, new TypeReference>() { + }); + result.getData().setOutput(output); + return result; + } + } + return null; } private T makeRequest(Request request, TypeReference typeReference) throws Exception { diff --git a/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/Result.java b/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/Result.java index 01a87978..49be4881 100644 --- a/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/Result.java +++ b/inngest-spring-boot-demo/src/main/java/com/inngest/springbootdemo/Result.java @@ -1,12 +1,18 @@ package com.inngest.springbootdemo; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; -public class Result { - @JsonProperty("sum") - public final int sum; +@Getter +@Setter +@JsonIgnoreProperties(ignoreUnknown = true) +@NoArgsConstructor +class Result { + int sum; - public Result(@JsonProperty("sum") int sum) { + Result(int sum) { this.sum = sum; } } diff --git a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/CustomStepResultIntegrationTest.java b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/CustomStepResultIntegrationTest.java new file mode 100644 index 00000000..4ca9d980 --- /dev/null +++ b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/CustomStepResultIntegrationTest.java @@ -0,0 +1,42 @@ +package com.inngest.springbootdemo; + +import com.inngest.CommHandler; +import com.inngest.Inngest; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@IntegrationTest +@Execution(ExecutionMode.CONCURRENT) +class CustomStepResultIntegrationTest { + @BeforeAll + static void setup(@Autowired CommHandler handler) { + handler.register(); + } + + @Autowired + private DevServerComponent devServer; + + static int sleepTime = 5000; + + @Autowired + private Inngest client; + + + @Test + void testMultiStepsFunctionWithClassResultStep() throws Exception { + String eventId = InngestFunctionTestHelpers.sendEvent(client, "test/custom.result.step").first(); + + Thread.sleep(sleepTime); + + RunEntry run = devServer.runsByEvent(eventId).first(); + RunEntry runWithOutput = devServer.runById(run.getRun_id(), Result.class).getData(); + + assertEquals(runWithOutput.getStatus(), "Completed"); + assertEquals(runWithOutput.getOutput().getSum(), (new Result(5).getSum())); + } +} diff --git a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/DemoTestConfiguration.java b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/DemoTestConfiguration.java index e564733a..50477f30 100644 --- a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/DemoTestConfiguration.java +++ b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/DemoTestConfiguration.java @@ -14,6 +14,7 @@ protected HashMap functions() { addInngestFunction(functions, InngestFunctionTestHelpers.emptyStepFunction()); addInngestFunction(functions, InngestFunctionTestHelpers.sleepStepFunction()); addInngestFunction(functions, InngestFunctionTestHelpers.twoStepsFunction()); + addInngestFunction(functions, InngestFunctionTestHelpers.customStepResultFunction()); addInngestFunction(functions, InngestFunctionTestHelpers.waitForEventFunction()); addInngestFunction(functions, InngestFunctionTestHelpers.sendEventFunction()); addInngestFunction(functions, InngestFunctionTestHelpers.nonRetriableErrorFunction()); diff --git a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/InngestFunctionTestHelpers.java b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/InngestFunctionTestHelpers.java index b7ee2f67..71089552 100644 --- a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/InngestFunctionTestHelpers.java +++ b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/InngestFunctionTestHelpers.java @@ -62,6 +62,29 @@ static InngestFunction twoStepsFunction() { return new InngestFunction(fnConfig, handler); } + static InngestFunction customStepResultFunction() { + FunctionTrigger fnTrigger = new FunctionTrigger("test/custom.result.step"); + FunctionTrigger[] triggers = {fnTrigger}; + FunctionOptions fnConfig = new FunctionOptions("custom-result-fn", "Custom Result Function", triggers); + + int count = 0; + + BiFunction handler = (ctx, step) -> { + int step1 = step.run("step1", () -> count + 1, Integer.class); + int tmp1 = step1 + 1; + + int step2 = step.run("step2", () -> tmp1 + 1, Integer.class); + int tmp2 = step2 + 1; + + return step.run("cast-to-type-add-one", () -> { + System.out.println("-> running step 1!! " + tmp2); + return new Result(tmp2 + 1); + }, Result.class); + }; + + return new InngestFunction(fnConfig, handler); + } + static InngestFunction waitForEventFunction() { FunctionTrigger fnTrigger = new FunctionTrigger("test/wait-for-event"); FunctionTrigger[] triggers = {fnTrigger}; diff --git a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/SleepFunctionIntegrationTest.java b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/SleepFunctionIntegrationTest.java index 6883bc08..6f4a3e83 100644 --- a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/SleepFunctionIntegrationTest.java +++ b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/SleepFunctionIntegrationTest.java @@ -38,7 +38,7 @@ void testSleepFunctionRunningSuccessfully() throws Exception { Thread.sleep(10000); - RunEntry updatedRun = devServer.runById(run.getRun_id()).getData(); + RunEntry updatedRun = devServer.runById(run.getRun_id(), Integer.class).getData(); assertEquals(updatedRun.getEvent_id(), eventId); assertEquals(updatedRun.getStatus(), "Completed"); diff --git a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/WaitForEventFunctionIntegrationTest.java b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/WaitForEventFunctionIntegrationTest.java index 625c155b..a935a0ca 100644 --- a/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/WaitForEventFunctionIntegrationTest.java +++ b/inngest-spring-boot-demo/src/test/java/com/inngest/springbootdemo/WaitForEventFunctionIntegrationTest.java @@ -43,7 +43,7 @@ void testWaitForEventFunctionWhenFullFilled() throws Exception { Thread.sleep(sleepTime); - RunEntry updatedRun = devServer.runById(run.getRun_id()).getData(); + RunEntry updatedRun = devServer.runById(run.getRun_id(), Object.class).getData(); assertEquals(updatedRun.getEvent_id(), eventId); assertEquals(updatedRun.getRun_id(), run.getRun_id()); @@ -65,7 +65,7 @@ void testWaitForEventFunctionWhenTimeOut() throws Exception { Thread.sleep(sleepTime); - RunEntry updatedRun = devServer.runById(run.getRun_id()).getData(); + RunEntry updatedRun = devServer.runById(run.getRun_id(), String.class).getData(); assertEquals(updatedRun.getEvent_id(), eventId); assertEquals(updatedRun.getRun_id(), run.getRun_id());