Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/state_machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export class DurableExecutionStateMachine<I, O> implements RestateContext {

const msg = GetStateEntryMessage.create({ key: Buffer.from(name) });

const promise = this.storePendingMsg(
const promise = this.storePendingMsg<Buffer | Empty>(
this.currentJournalIndex,
GET_STATE_ENTRY_MESSAGE_TYPE,
msg
Expand All @@ -193,10 +193,15 @@ export class DurableExecutionStateMachine<I, O> 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;
}
}

Expand Down
145 changes: 144 additions & 1 deletion test/get_state.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use strict";

import { describe, expect } from "@jest/globals";
import * as restate from "../src/public_api";
import { TestDriver } from "./testdriver";
Expand Down Expand Up @@ -25,12 +27,44 @@ class GetStateGreeter implements TestGreeter {
const ctx = restate.useContext(this);

// state
const state = (await ctx.get<string>("STATE")) || "nobody";
let state = await ctx.get<string>("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<TestResponse> {
const ctx = restate.useContext(this);

// state
const state = (await ctx.get<number>("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<TestResponse> {
const ctx = restate.useContext(this);

// state
const state = await ctx.get<number[]>("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(
Expand Down Expand Up @@ -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")
),
]);
});
});