diff --git a/src/state_machine.ts b/src/state_machine.ts index 70bc4ea4..3d52d2f8 100644 --- a/src/state_machine.ts +++ b/src/state_machine.ts @@ -174,7 +174,7 @@ export class DurableExecutionStateMachine implements RestateContext { const msg = GetStateEntryMessage.create({ key: Buffer.from(name) }); - const promise = this.storePendingMsg( + const promise = this.storePendingMsg( this.currentJournalIndex, GET_STATE_ENTRY_MESSAGE_TYPE, msg @@ -193,10 +193,15 @@ export class DurableExecutionStateMachine implements RestateContext { const result = await promise; - if (result == null || JSON.stringify(result) === "{}") { - return null; + if (result instanceof Buffer) { + const resultString = result.toString(); + if (resultString === "0") { + return resultString as T; + } + + return JSON.parse(resultString) as T; } else { - return JSON.parse(result.toString()) as T; + return null; } } diff --git a/test/get_state.test.ts b/test/get_state.test.ts index 95a8e67e..9d63adbc 100644 --- a/test/get_state.test.ts +++ b/test/get_state.test.ts @@ -1,3 +1,5 @@ +"use strict"; + import { describe, expect } from "@jest/globals"; import * as restate from "../src/public_api"; import { TestDriver } from "./testdriver"; @@ -25,12 +27,44 @@ class GetStateGreeter implements TestGreeter { const ctx = restate.useContext(this); // state - const state = (await ctx.get("STATE")) || "nobody"; + let state = await ctx.get("STATE"); + if (state === null) { + state = "nobody"; + } + + return TestResponse.create({ greeting: `Hello ${state}` }); + } +} + +class NumberGetStateGreeter implements TestGreeter { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async greet(request: TestRequest): Promise { + const ctx = restate.useContext(this); + + // state + const state = (await ctx.get("STATE")) || 0; return TestResponse.create({ greeting: `Hello ${state}` }); } } +class NumberListGetStateGreeter implements TestGreeter { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async greet(request: TestRequest): Promise { + const ctx = restate.useContext(this); + + // state + const state = await ctx.get("STATE"); + if (state) { + return TestResponse.create({ + greeting: `Hello index 0: ${state[0]} - index 1: ${state[1]}`, + }); + } else { + return TestResponse.create({ greeting: `Hello no state found` }); + } + } +} + describe("GetStateGreeter: With GetStateEntry already complete", () => { it("should call greet", async () => { const result = await new TestDriver( @@ -127,3 +161,112 @@ describe("GetStateGreeter: Without GetStateEntry and completed with later Comple ]); }); }); + +describe("GetStateGreeter: Without GetStateEntry and completed with later CompletionFrame with empty string", () => { + it("should call greet", async () => { + const result = await new TestDriver( + protoMetadata, + "TestGreeter", + new GetStateGreeter(), + "/test.TestGreeter/Greet", + [ + startMessage(1), + inputMessage(greetRequest("Till")), + completionMessage(1, Buffer.from(JSON.stringify(""))), + ] + ).run(); + + expect(result).toStrictEqual([ + getStateMessage("STATE"), + outputMessage(greetResponse("Hello ")), + ]); + }); +}); + +describe("NumberGetStateGreeter: Without GetStateEntry and completed with later CompletionFrame with numeric value 70", () => { + it("should call greet", async () => { + const result = await new TestDriver( + protoMetadata, + "TestGreeter", + new NumberGetStateGreeter(), + "/test.TestGreeter/Greet", + [ + startMessage(1), + inputMessage(greetRequest("Till")), + completionMessage(1, Buffer.from(JSON.stringify(70))), + ] + ).run(); + + expect(result).toStrictEqual([ + getStateMessage("STATE"), + outputMessage(greetResponse("Hello 70")), + ]); + }); +}); + +describe("NumberGetStateGreeter: Without GetStateEntry and completed with later CompletionFrame with value 0", () => { + it("should call greet", async () => { + const result = await new TestDriver( + protoMetadata, + "TestGreeter", + new NumberGetStateGreeter(), + "/test.TestGreeter/Greet", + [ + startMessage(1), + inputMessage(greetRequest("Till")), + completionMessage(1, Buffer.from(JSON.stringify(0))), + ] + ).run(); + + expect(result).toStrictEqual([ + getStateMessage("STATE"), + outputMessage(greetResponse("Hello 0")), + ]); + }); +}); + +describe("NumberListGetStateGreeter: Without GetStateEntry and completed with later CompletionFrame with list state", () => { + it("should call greet", async () => { + const result = await new TestDriver( + protoMetadata, + "TestGreeter", + new NumberListGetStateGreeter(), + "/test.TestGreeter/Greet", + [ + startMessage(1), + inputMessage(greetRequest("Till")), + completionMessage(1, Buffer.from(JSON.stringify([5, 4]))), + ] + ).run(); + + expect(result).toStrictEqual([ + getStateMessage("STATE"), + outputMessage(greetResponse("Hello index 0: 5 - index 1: 4")), + ]); + }); +}); + +describe("NumberListGetStateGreeter: Without GetStateEntry and completed with later CompletionFrame with empty list state", () => { + it("should call greet", async () => { + const result = await new TestDriver( + protoMetadata, + "TestGreeter", + new NumberListGetStateGreeter(), + "/test.TestGreeter/Greet", + [ + startMessage(1), + inputMessage(greetRequest("Till")), + completionMessage(1, Buffer.from(JSON.stringify([]))), + ] + ).run(); + + // For an empty list it will print undefined values for the first two indices + // but still recognize it as a list + expect(result).toStrictEqual([ + getStateMessage("STATE"), + outputMessage( + greetResponse("Hello index 0: undefined - index 1: undefined") + ), + ]); + }); +});