Skip to content

Update test suite to 3.0 #495

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
3 changes: 2 additions & 1 deletion .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,10 @@ jobs:
cache-to: type=gha,mode=max,scope=${{ github.workflow }}

- name: Run test tool
uses: restatedev/sdk-test-suite@v2.4
uses: restatedev/sdk-test-suite@v3.0
with:
restateContainerImage: ${{ inputs.restateCommit != '' && 'localhost/restatedev/restate-commit-download:latest' || (inputs.restateImage != '' && inputs.restateImage || 'ghcr.io/restatedev/restate:main') }}
serviceContainerImage: "restatedev/typescript-test-services"
exclusionsFile: "packages/restate-e2e-services/exclusions.yaml"
testArtifactOutput: "sdk-typescript-integration-test-report"
serviceContainerEnvFile: "packages/restate-e2e-services/.env"
1 change: 1 addition & 0 deletions packages/restate-e2e-services/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
RESTATE_LOGGING=TRACE
27 changes: 26 additions & 1 deletion packages/restate-e2e-services/exclusions.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
exclusions: {}
exclusions:
"alwaysSuspending":
- "dev.restate.sdktesting.tests.Cancellation.cancelFromContext"
- "dev.restate.sdktesting.tests.Combinators.awakeableOrTimeoutUsingAwaitAny"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.callWithIdempotencyKey"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.oneWayCallWithIdempotencyKey"
"default":
- "dev.restate.sdktesting.tests.Cancellation.cancelFromContext"
- "dev.restate.sdktesting.tests.Combinators.awakeableOrTimeoutUsingAwaitAny"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.callWithIdempotencyKey"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.oneWayCallWithIdempotencyKey"
"singleThreadSinglePartition":
- "dev.restate.sdktesting.tests.Cancellation.cancelFromContext"
- "dev.restate.sdktesting.tests.Combinators.awakeableOrTimeoutUsingAwaitAny"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.callWithIdempotencyKey"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.oneWayCallWithIdempotencyKey"
"threeNodes":
- "dev.restate.sdktesting.tests.Cancellation.cancelFromContext"
- "dev.restate.sdktesting.tests.Combinators.awakeableOrTimeoutUsingAwaitAny"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.callWithIdempotencyKey"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.oneWayCallWithIdempotencyKey"
"threeNodesAlwaysSuspending":
- "dev.restate.sdktesting.tests.Cancellation.cancelFromContext"
- "dev.restate.sdktesting.tests.Combinators.awakeableOrTimeoutUsingAwaitAny"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.callWithIdempotencyKey"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication.oneWayCallWithIdempotencyKey"
1 change: 1 addition & 0 deletions packages/restate-e2e-services/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import "./workflow.js";
import "./proxy.js";
import "./test_utils.js";
import "./kill.js";
import "./virtual_object_command_interpreter.js";

import { REGISTRY } from "./services.js";

Expand Down
4 changes: 1 addition & 3 deletions packages/restate-e2e-services/src/cancel_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ const blockingService = restate.object({
handlers: {
async block(ctx: restate.ObjectContext, request: BlockingOperation) {
const { id, promise } = ctx.awakeable();
// DO NOT await the next CALL otherwise the test deadlocks.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
ctx.objectClient(AwakeableHolder, "cancel").hold(id);
await ctx.objectClient(AwakeableHolder, ctx.key).hold(id);
await promise;

switch (request) {
Expand Down
10 changes: 5 additions & 5 deletions packages/restate-e2e-services/src/kill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import * as restate from "@restatedev/restate-sdk";
import { REGISTRY } from "./services.js";
import type { AwakeableHolder } from "./awakeable_holder.js";

const kill = restate.service({
const kill = restate.object({
name: "KillTestRunner",
handlers: {
async startCallTree(ctx: restate.ObjectContext) {
await ctx.objectClient(killSingleton, "").recursiveCall();
await ctx.objectClient(killSingleton, ctx.key).recursiveCall();
},
},
});
Expand All @@ -26,11 +26,11 @@ const killSingleton = restate.object({
async recursiveCall(ctx: restate.ObjectContext) {
const { id, promise } = ctx.awakeable();
ctx
.objectSendClient<AwakeableHolder>({ name: "AwakeableHolder" }, "kill")
.objectSendClient<AwakeableHolder>({ name: "AwakeableHolder" }, ctx.key)
.hold(id);
await promise;

await ctx.objectClient(killSingleton, "").recursiveCall();
await ctx.objectClient(killSingleton, ctx.key).recursiveCall();
},

isUnlocked() {
Expand All @@ -39,5 +39,5 @@ const killSingleton = restate.object({
},
});

REGISTRY.addService(kill);
REGISTRY.addObject(kill);
REGISTRY.addObject(killSingleton);
18 changes: 15 additions & 3 deletions packages/restate-e2e-services/src/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@

import * as restate from "@restatedev/restate-sdk";
import { REGISTRY } from "./services.js";
import { TerminalError } from "@restatedev/restate-sdk";

type ProxyRequest = {
serviceName: string;
virtualObjectKey?: string;
handlerName: string;
message: Array<number>;
delayMillis?: number;
idempotencyKey?: string;
};

type ManyCallRequest = {
Expand All @@ -30,6 +32,10 @@ function rawCall(
ctx: restate.Context,
request: ProxyRequest
): Promise<Uint8Array> {
// TODO add idempotency key support here
if (request.idempotencyKey != undefined) {
throw new TerminalError("idempotency key not supported yet");
}
return ctx.genericCall({
service: request.serviceName,
method: request.handlerName,
Expand All @@ -40,7 +46,11 @@ function rawCall(
});
}

function rawSend(ctx: restate.Context, request: ProxyRequest) {
function rawSend(ctx: restate.Context, request: ProxyRequest): Promise<string> {
// TODO add idempotency key support here
if (request.idempotencyKey != undefined) {
throw new TerminalError("idempotency key not supported yet");
}
ctx.genericSend({
service: request.serviceName,
method: request.handlerName,
Expand All @@ -49,6 +59,8 @@ function rawSend(ctx: restate.Context, request: ProxyRequest) {
parameter: new Uint8Array(request.message),
delay: request.delayMillis,
});
// TODO this should return the invocation id
return Promise.resolve("unknown");
}

const o = restate.service({
Expand All @@ -59,15 +71,15 @@ const o = restate.service({
},

async oneWayCall(ctx: restate.Context, request: ProxyRequest) {
rawSend(ctx, request);
return rawSend(ctx, request);
},

async manyCalls(ctx: restate.Context, request: ManyCallRequest[]) {
const toAwait = [];

for (const r of request) {
if (r.oneWayCall) {
rawSend(ctx, r.proxyRequest);
await rawSend(ctx, r.proxyRequest);
continue;
}
const promise = rawCall(ctx, r.proxyRequest);
Expand Down
79 changes: 8 additions & 71 deletions packages/restate-e2e-services/src/test_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,7 @@
import * as restate from "@restatedev/restate-sdk";
import { REGISTRY } from "./services.js";

import type { AwakeableHolder } from "./awakeable_holder.js";
import * as process from "node:process";
import { ListObject } from "./list.js";

const AwakeableHolder: AwakeableHolder = { name: "AwakeableHolder" };
const ListObject: ListObject = { name: "ListObject" };

type Command =
| { type: "createAwakeableAndAwaitIt"; awakeableKey: string }
| { type: "getEnvVariable"; envName: string };

interface InterpretRequest {
listName: string;
commands: Command[];
}
import { TerminalError } from "@restatedev/restate-sdk";

const o = restate.service({
name: "TestUtilsService",
Expand All @@ -51,29 +37,6 @@ const o = restate.service({
}
),

async createAwakeableAndAwaitIt(
ctx: restate.Context,
req: { awakeableKey: string; awaitTimeout?: number }
): Promise<{ type: "timeout" } | { type: "result"; value: string }> {
const { id, promise } = ctx.awakeable<string>();

await ctx.objectClient(AwakeableHolder, req.awakeableKey).hold(id);

if (!req.awaitTimeout) {
return { type: "result", value: await promise };
}

try {
const res = await promise.orTimeout(req.awaitTimeout);
return { type: "result", value: res };
} catch (e) {
if (e instanceof restate.TimeoutError) {
return { type: "timeout" };
}
throw e;
}
},

async sleepConcurrently(
ctx: restate.Context,
millisDuration: number[]
Expand Down Expand Up @@ -102,42 +65,16 @@ const o = restate.service({
return invokedSideEffects;
},

async getEnvVariable(ctx: restate.Context, env: string): Promise<string> {
return ctx.run(() => process.env[env] ?? "");
},

async interpretCommands(
async cancelInvocation(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
ctx: restate.Context,
req: InterpretRequest
// eslint-disable-next-line @typescript-eslint/no-unused-vars
invocationId: string
): Promise<void> {
const listClient = ctx.objectSendClient(ListObject, req.listName);

async function createAwakeableAndAwaitIt(
awakeableKey: string
): Promise<string> {
const { id, promise } = ctx.awakeable<string>();
await ctx.objectClient(AwakeableHolder, awakeableKey).hold(id);
return promise;
}

async function getEnvVariable(envName: string): Promise<string> {
return ctx.run(() => process.env[envName] ?? "");
}

for (const command of req.commands) {
switch (command.type) {
case "createAwakeableAndAwaitIt":
listClient.append(
await createAwakeableAndAwaitIt(command.awakeableKey)
);
break;
case "getEnvVariable":
listClient.append(await getEnvVariable(command.envName));
break;
}
}
// TODO add cancel invocation here!
return Promise.reject(new TerminalError("cancel is not supported yet"));
},
},
});

REGISTRY.addObject(o);
REGISTRY.addService(o);
Loading