Skip to content

Commit ab6511a

Browse files
authored
Add runnable target for e2e test CDK stacks (#60)
1 parent b54f5d0 commit ab6511a

19 files changed

+291
-62
lines changed

Diff for: .gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
.idea
2+
.zed
23
*.js
3-
!jest.config.js
4+
*.sh
5+
!jest.config*.js
46
!test/handlers/handler.js
57
*.d.ts
68
node_modules

Diff for: jest.config.base.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
testEnvironment: "node",
3+
transform: {
4+
"^.+\\.tsx?$": "ts-jest",
5+
},
6+
};

Diff for: jest.config.e2e.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const baseConfig = require("./jest.config.base");
2+
3+
module.exports = {
4+
...baseConfig,
5+
roots: ["<rootDir>/test"],
6+
testMatch: ["<rootDir>/test/e2e/**/*.e2e.ts"],
7+
testTimeout: 600_000,
8+
};

Diff for: jest.config.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
const baseConfig = require("./jest.config.base");
2+
13
module.exports = {
2-
testEnvironment: "node",
4+
...baseConfig,
35
roots: ["<rootDir>/test"],
4-
testMatch: ["**/*.test.ts"],
5-
transform: {
6-
"^.+\\.tsx?$": "ts-jest",
7-
},
6+
testMatch: ["<rootDir>/test/**/*.test.ts"],
7+
// Exclude E2E tests
8+
testPathIgnorePatterns: ["/node_modules/", "/test/e2e/"],
89
};

Diff for: package-lock.json

+47-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"prebundle": "rm -rf dist",
2121
"postbundle": "cd dist && zip -r index.zip index.js*",
2222
"watch": "tsc -w",
23-
"test": "jest",
23+
"test": "jest --config jest.config.js",
24+
"test:e2e": "npx tsx test/handlers/build.mts && jest --config jest.config.e2e.js",
2425
"lint": "npx prettier --check .",
2526
"cdk": "cdk"
2627
},
@@ -37,7 +38,8 @@
3738
"source-map-support": "^0.5.21",
3839
"ts-jest": "^29.2.5",
3940
"tsx": "^4.19.2",
40-
"typescript": "^5.7.0"
41+
"typescript": "^5.7.0",
42+
"zx": "^8.3.2"
4143
},
4244
"peerDependencies": {
4345
"@aws-sdk/client-secrets-manager": "^3.637.0",

Diff for: test/e2e/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
## Restate CDK e2e tests
2+
3+
The CDK stacks in this directory serve a dual purpose of providing usage examples, and validation targets during development.
4+
5+
Some of these are wrapped in e2e tests you can run with:
6+
7+
```shell
8+
npm run test:e2e
9+
```
10+
11+
To run the automated e2e tests, you'll generally need valid AWS or Restate Cloud credentials. To speed things up you can set `RETAIN_STACK=true`.

Diff for: test/e2e/cdk-util.ts

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2023-2025 - Restate Software, Inc., Restate GmbH
3+
*
4+
* This file is part of the Restate SDK for Node.js/TypeScript,
5+
* which is released under the MIT license.
6+
*
7+
* You can find a copy of the license in file LICENSE in the root
8+
* directory of this repository or package, or at
9+
* https://github.com/restatedev/cdk/blob/main/LICENSE
10+
*/
11+
12+
import { $, cd, path } from "zx";
13+
14+
export interface CdkStackProps {
15+
stackName: string;
16+
cdkAppPath: string;
17+
}
18+
19+
interface StackOutput {
20+
OutputKey: string;
21+
OutputValue: string;
22+
Description?: string;
23+
}
24+
25+
export async function createStack(config: CdkStackProps): Promise<Record<string, string>> {
26+
const retainStack = new Boolean(process.env["RETAIN_STACK"]).valueOf();
27+
28+
cd(path.resolve(__dirname));
29+
await $`npx cdk --app 'npx tsx ${config.cdkAppPath}' deploy \
30+
--context stack_name="${config.stackName}" \
31+
--output "cdk.${config.stackName}.out" \
32+
--require-approval never \
33+
${retainStack ? "--no-rollback" : ""}`.timeout("575s");
34+
35+
const result =
36+
await $`aws cloudformation describe-stacks --stack-name "${config.stackName}" --query 'Stacks[0].Outputs'`;
37+
38+
const outputs: StackOutput[] = JSON.parse(result.stdout);
39+
return outputs.reduce(
40+
(acc, output) => ({
41+
...acc,
42+
[output.OutputKey]: output.OutputValue,
43+
}),
44+
{},
45+
);
46+
}
47+
48+
export async function destroyStackAsync(stackName: string) {
49+
const retainStack = new Boolean(process.env["RETAIN_STACK"]).valueOf();
50+
51+
if (retainStack) {
52+
console.log(`Retaining stack "${stackName}"`);
53+
} else {
54+
console.log(`Asynchronously deleting stack "${stackName}"...`);
55+
await $`aws cloudformation delete-stack --stack-name "${stackName}"`;
56+
}
57+
}
58+
59+
export async function destroyStack(config: CdkStackProps) {
60+
const retainStack = new Boolean(process.env["RETAIN_STACK"]).valueOf();
61+
62+
if (retainStack) {
63+
console.log(`Retaining stack "${config.stackName}"`);
64+
} else {
65+
await $`npx cdk --app 'npx tsx ${config.cdkAppPath}' destroy \
66+
--context stack_name=${config.stackName} \
67+
--output "cdk.${config.stackName}.out" \
68+
--force`.timeout("595s");
69+
}
70+
}

Diff for: test/e2e/deploy-ec2-alb.sh

-12
This file was deleted.

Diff for: test/e2e/deploy-ec2-direct.sh

-8
This file was deleted.

Diff for: test/e2e/deploy-restate-cloud-lambda.e2e.sh

-11
This file was deleted.

Diff for: test/e2e/destroy-ec2-alb.sh

-11
This file was deleted.
File renamed without changes.

Diff for: test/e2e/single-node-ec2.e2e.ts renamed to test/e2e/ec2-simple-stack.ts

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,32 @@
11
/*
2-
* Copyright (c) 2024 - Restate Software, Inc., Restate GmbH
2+
* Copyright (c) 2023-2025 - Restate Software, Inc., Restate GmbH
33
*
44
* This file is part of the Restate SDK for Node.js/TypeScript,
55
* which is released under the MIT license.
66
*
77
* You can find a copy of the license in file LICENSE in the root
88
* directory of this repository or package, or at
9-
* https://github.com/restatedev/sdk-typescript/blob/main/LICENSE
9+
* https://github.com/restatedev/cdk/blob/main/LICENSE
1010
*/
1111

1212
import * as cdk from "aws-cdk-lib";
13+
import * as ec2 from "aws-cdk-lib/aws-ec2";
1314
import * as lambda from "aws-cdk-lib/aws-lambda";
1415
import * as logs from "aws-cdk-lib/aws-logs";
15-
import "source-map-support/register";
16-
1716
import { ServiceDeployer, SingleNodeRestateDeployment } from "../../lib/restate-constructs";
18-
import * as ec2 from "aws-cdk-lib/aws-ec2";
1917

20-
// Deploy with: npx cdk --app 'npx tsx single-node-ec2.e2e.ts' deploy --context vpc_id=...
18+
// Deploy with: npx cdk --app 'npx tsx ec2-simple-stack.ts' deploy --context vpc_id=...
2119
const app = new cdk.App();
22-
const stack = new cdk.Stack(app, "e2e-RestateSingleNode", {
20+
const stackName = app.node.tryGetContext("stack_name") ?? "e2e-RestateSingleNode";
21+
const stack = new cdk.Stack(app, stackName, {
2322
env: {
2423
account: process.env.CDK_DEFAULT_ACCOUNT,
2524
region: process.env.CDK_DEFAULT_REGION,
2625
},
2726
});
2827

2928
const handler: lambda.Function = new lambda.Function(stack, "Service", {
30-
runtime: lambda.Runtime.NODEJS_LATEST,
29+
runtime: lambda.Runtime.NODEJS_22_X,
3130
code: lambda.Code.fromAsset("../handlers/dist/"),
3231
handler: "bundle.handler",
3332
});
@@ -55,8 +54,8 @@ const environment = new SingleNodeRestateDeployment(stack, "Restate", {
5554
// Safer option: add the deployer to the VPC + security group
5655
const deployer = new ServiceDeployer(stack, "ServiceDeployer", {
5756
vpc: environment.vpc,
58-
allowPublicSubnet: true, // necessary to deploy to a public subnet - it's ok, deployer doesn't need the internet
59-
securityGroups: [environment.adminSecurityGroup],
57+
allowPublicSubnet: true, // necessary to deploy to a public VPC subnet - no internet access but we don't need it
58+
securityGroups: [environment.adminSecurityGroup], // the admin SG can access the admin port 9070
6059
removalPolicy: cdk.RemovalPolicy.DESTROY,
6160
entry: "../../dist/register-service-handler/index.js", // only needed for in-tree tests
6261
});

0 commit comments

Comments
 (0)