Skip to content
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

Add @restate/restate-sdk-testcontainers #460

Merged
merged 8 commits into from
Nov 4, 2024
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
1,564 changes: 1,476 additions & 88 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"packages/restate-sdk-cloudflare-workers",
"packages/restate-sdk-clients",
"packages/restate-sdk-examples",
"packages/restate-sdk-testcontainers",
"packages/restate-e2e-services"
],
"type": "module",
Expand Down
4 changes: 3 additions & 1 deletion packages/restate-sdk-examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
"@restatedev/restate-sdk-clients": "^1.4.0"
},
"devDependencies": {
"tsx": "^4.15.7"
"tsx": "^4.15.7",
"@restatedev/restate-sdk-testcontainers": "^1.4.0",
"testcontainers": "^10.4.0"
},
"engines": {
"node": ">= 18.13"
Expand Down
2 changes: 1 addition & 1 deletion packages/restate-sdk-examples/src/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import * as restate from "@restatedev/restate-sdk";

const counter = restate.object({
export const counter = restate.object({
name: "counter",
handlers: {
/**
Expand Down
149 changes: 149 additions & 0 deletions packages/restate-sdk-examples/test/testcontainers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate SDK for Node.js/TypeScript,
* which is released under the MIT license.
*
* You can find a copy of the license in file LICENSE in the root
* directory of this repository or package, or at
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
*/

import { RestateTestEnvironment } from "@restatedev/restate-sdk-testcontainers";
import { counter } from "../src/object.js";
import * as clients from "@restatedev/restate-sdk-clients";
import * as core from "@restatedev/restate-sdk-core";
import { describe, it, beforeAll, afterAll, expect } from "vitest";
import { GenericContainer } from "testcontainers";

describe("ExampleObject", () => {
let restateTestEnvironment: RestateTestEnvironment;
let rs: clients.Ingress;

const serviceKey = "foo";

// Deploy Restate and the Service endpoint once for all the tests in this suite
beforeAll(async () => {
restateTestEnvironment = await RestateTestEnvironment.start(
(restateServer) => restateServer.bind(counter)
);
rs = clients.connect({ url: restateTestEnvironment.baseUrl() });
}, 20_000);

// Stop Restate and the Service endpoint
afterAll(async () => {
if (restateTestEnvironment !== undefined) {
await restateTestEnvironment.stop();
}
});

it("Can read state", async () => {
const state = restateTestEnvironment.stateOf(counter, serviceKey);

// State reading
expect(await state.getAll()).toStrictEqual({});
expect(await state.get("count")).toBeNull();
});

it("Can call methods", async () => {
const client = rs.objectClient(counter, serviceKey);

const count = await client.add(1);

expect(count).toBe(1);
});

it("Can write state", async () => {
const state = restateTestEnvironment.stateOf(counter, serviceKey);

await state.setAll({
count: 123,
});
expect(await state.getAll()).toStrictEqual({ count: 123 });

await state.set("count", 321);
expect(await state.get<number>("count")).toStrictEqual(321);
});

it("Can operate on state with non-JSON serde", async () => {
const state = restateTestEnvironment.stateOf(counter, serviceKey);

// State operations with non-JSON serde
await state.setAll(
{
count: new Uint8Array([49, 50]), // 12
},
core.serde.binary
);
expect(
await state.getAll<{ count: Uint8Array }>(core.serde.binary)
).toStrictEqual({
count: new Uint8Array([49, 50]),
});

await state.set(
"count",
new Uint8Array([49, 52]), // 14
core.serde.binary
);
expect(
await state.get<Uint8Array>("count", core.serde.binary)
).toStrictEqual(new Uint8Array([49, 52]));
});

it("Can operate on typed state", async () => {
// Typed state
const state = restateTestEnvironment.stateOf<{
count: number;
}>(counter, serviceKey);

await state.setAll({ count: 1 });
// wont compile:
// state.setAll({ count: "a" });
// state.setAll({ foo: 1 });

expect(await state.getAll()).toStrictEqual({ count: 1 });
// wont compile:
// (await state.getAll()) satisfies { count: string };
// (await state.getAll()) satisfies { foo: number };

await state.set("count", 2);
// wont compile:
// state.set("count", "a");
// state.set("foo", 2);

expect(await state.get("count")).toStrictEqual(2);
// wont compile:
// await state.get("foo");
// (await state.get("count")) satisfies string;
});
});

describe("Custom testcontainer config", () => {
let restateTestEnvironment: RestateTestEnvironment;

// Deploy Restate and the Service endpoint once for all the tests in this suite
beforeAll(async () => {
restateTestEnvironment = await RestateTestEnvironment.start(
(restateServer) => restateServer.bind(counter),
() =>
new GenericContainer("restatedev/restate:1.1")
.withEnvironment({ RESTATE_LOG_FORMAT: "json" })
.withLogConsumer((stream) => {
// eslint-disable-next-line no-console
stream.on("data", (line) => console.info(line));
// eslint-disable-next-line no-console
stream.on("err", (line) => console.error(line));
})
);
}, 20_000);

// Stop Restate and the Service endpoint
afterAll(async () => {
if (restateTestEnvironment !== undefined) {
await restateTestEnvironment.stop();
}
});

it("Works", () => {});
});
5 changes: 4 additions & 1 deletion packages/restate-sdk-examples/tsconfig.eslint.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "test/**/*.ts"],
"references": [{ "path": "../restate-sdk-core" }]
"references": [
{ "path": "../restate-sdk-core" },
{ "path": "../restate-sdk-testcontainers" }
]
}
3 changes: 2 additions & 1 deletion packages/restate-sdk-examples/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"references": [
{ "path": "../restate-sdk-core" },
{ "path": "../restate-sdk" },
{ "path": "../restate-sdk-clients" }
{ "path": "../restate-sdk-clients" },
{ "path": "../restate-sdk-testcontainers" }
]
}
3 changes: 3 additions & 0 deletions packages/restate-sdk-testcontainers/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
src/generated
31 changes: 31 additions & 0 deletions packages/restate-sdk-testcontainers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[![Documentation](https://img.shields.io/badge/doc-reference-blue)](https://docs.restate.dev)
[![Examples](https://img.shields.io/badge/view-examples-blue)](https://github.com/restatedev/examples)
[![Discord](https://img.shields.io/discord/1128210118216007792?logo=discord)](https://discord.gg/skW3AZ6uGd)
[![Twitter](https://img.shields.io/twitter/follow/restatedev.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=restatedev)

# Restate Typescript SDK Test Containers

[Restate](https://restate.dev/) is a system for easily building resilient applications using *distributed durable async/await*.

This package contains utilities to test Restate SDK services against a Restate server container.
An usage example can be found in [`restate-sdk-examples/test/testcontainers.test.ts`](../restate-sdk-examples/test/testcontainers.test.ts)

## Community

* 🤗️ [Join our online community](https://discord.gg/skW3AZ6uGd) for help, sharing feedback and talking to the community.
* 📖 [Check out our documentation](https://docs.restate.dev) to get quickly started!
* 📣 [Follow us on Twitter](https://twitter.com/restatedev) for staying up to date.
* 🙋 [Create a GitHub issue](https://github.com/restatedev/sdk-typescript/issues) for requesting a new feature or reporting a problem.
* 🏠 [Visit our GitHub org](https://github.com/restatedev) for exploring other repositories.

## Using the library

To use this library, add the dependency to your project:

```shell
npm install --save-dev @restatedev/restate-sdk-testcontainers
```

## Versions

This library follows [Semantic Versioning](https://semver.org/).
63 changes: 63 additions & 0 deletions packages/restate-sdk-testcontainers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"name": "@restatedev/restate-sdk-testcontainers",
"version": "1.4.0",
"description": "Utils for testing services against a Restate container",
"author": "Restate Developers",
"license": "MIT",
"email": "[email protected]",
"homepage": "https://github.com/restatedev/sdk-typescript#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/restatedev/sdk-typescript.git"
},
"bugs": {
"url": "https://github.com/restatedev/sdk-typescript/issues"
},
"type": "module",
"sideEffects": false,
"main": "./dist/cjs/src/public_api.js",
"types": "./dist/cjs/src/public_api.d.ts",
"module": "./dist/esm/src/public_api.js",
"exports": {
".": {
"import": {
"types": "./dist/esm/src/public_api.d.ts",
"default": "./dist/esm/src/public_api.js"
},
"require": {
"types": "./dist/cjs/src/public_api.d.ts",
"default": "./dist/cjs/src/public_api.js"
}
}
},
"files": [
"dist"
],
"scripts": {
"build": "npm run build:cjs && npm run build:esm",
"build:cjs": "tsc --module commonjs --verbatimModuleSyntax false --moduleResolution node10 --outDir ./dist/cjs --declaration --declarationDir ./dist/cjs && echo >./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
"build:esm": "tsc --outDir ./dist/esm --declaration --declarationDir ./dist/esm",
"test": "vitest run --silent --passWithNoTests",
"lint": "eslint --ignore-path .eslintignore --max-warnings=0 --ext .ts .",
"format": "prettier --ignore-path .eslintignore --write \"**/*.+(js|ts|json)\"",
"format-check": "prettier --ignore-path .eslintignore --check \"**/*.+(js|ts|json)\"",
"attw": "attw --pack",
"verify": "npm run format-check && npm run lint && npm run test && npm run build && npm run attw",
"release": "release-it"
},
"dependencies": {
"@restatedev/restate-sdk-core": "^1.4.0",
"@restatedev/restate-sdk-clients": "^1.4.0",
"apache-arrow": "^18.0.0",
"testcontainers": "^10.4.0"
},
"engines": {
"node": ">= 18.13"
},
"directories": {
"test": "test"
},
"publishConfig": {
"@restatedev:registry": "https://registry.npmjs.org"
}
}
12 changes: 12 additions & 0 deletions packages/restate-sdk-testcontainers/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2023-2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate SDK for Node.js/TypeScript,
* which is released under the MIT license.
*
* You can find a copy of the license in file LICENSE in the root
* directory of this repository or package, or at
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
*/

export { RestateTestEnvironment } from "./restate_test_environment.js";
Loading