mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-05 00:56:23 +00:00
* fix(pr-to-video): bound first-run workspace and context * fix(cli): expose validation gate in help * fix(pr-to-video): harden workflow guardrails * style(pr-to-video): apply repository formatting * chore(skills): refresh pr-to-video manifest
141 lines
5.0 KiB
TypeScript
141 lines
5.0 KiB
TypeScript
/**
|
|
* Contract tests for {@link HyperframesRenderStack}.
|
|
*
|
|
* The snapshot test (in this directory's sibling `.snapshot.test.ts`)
|
|
* guards the full CloudFormation shape. The contract tests below pin
|
|
* the few properties whose drift would cause a real production
|
|
* regression — wrong Lambda runtime, lost reserved-concurrency knob,
|
|
* missing alarms — so we get a high-signal failure independent of
|
|
* the snapshot.
|
|
*/
|
|
|
|
import { beforeAll, describe, it } from "bun:test";
|
|
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { App, Stack } from "aws-cdk-lib";
|
|
import { Template } from "aws-cdk-lib/assertions";
|
|
import { HyperframesRenderStack } from "./HyperframesRenderStack.js";
|
|
|
|
// CDK synth is slow on cold start and reached 32s under full-workspace CI
|
|
// contention. The
|
|
// default bun:test 5s timeout trips the first `it()` that calls it. Cache
|
|
// the default-args synth in `beforeAll` so each test is pure assertions.
|
|
// Tests that need non-default props still synth on demand and bump their
|
|
// own per-test timeout.
|
|
let DEFAULT_TEMPLATE: Template;
|
|
|
|
function synthFixture(): Template {
|
|
const zipDir = mkdtempSync(join(tmpdir(), "hf-cdk-test-"));
|
|
const zipPath = join(zipDir, "handler.zip");
|
|
writeFileSync(zipPath, "fake zip bytes");
|
|
const app = new App();
|
|
const stack = new Stack(app, "TestStack");
|
|
new HyperframesRenderStack(stack, "Render", { handlerZipPath: zipPath });
|
|
return Template.fromStack(stack);
|
|
}
|
|
|
|
describe("HyperframesRenderStack — contract", () => {
|
|
beforeAll(() => {
|
|
DEFAULT_TEMPLATE = synthFixture();
|
|
}, 30000);
|
|
|
|
it("provisions exactly one Lambda function on the Node.js 22 runtime, x86_64, 10 GiB /tmp", () => {
|
|
const t = DEFAULT_TEMPLATE;
|
|
t.resourceCountIs("AWS::Lambda::Function", 1);
|
|
t.hasResourceProperties("AWS::Lambda::Function", {
|
|
Runtime: "nodejs22.x",
|
|
Architectures: ["x86_64"],
|
|
EphemeralStorage: { Size: 10240 },
|
|
MemorySize: 10240,
|
|
Handler: "handler.handler",
|
|
});
|
|
});
|
|
|
|
it("provisions exactly one Step Functions state machine of type STANDARD with tracing on", () => {
|
|
const t = DEFAULT_TEMPLATE;
|
|
t.resourceCountIs("AWS::StepFunctions::StateMachine", 1);
|
|
t.hasResourceProperties("AWS::StepFunctions::StateMachine", {
|
|
StateMachineType: "STANDARD",
|
|
TracingConfiguration: { Enabled: true },
|
|
});
|
|
});
|
|
|
|
it("provisions exactly one S3 bucket with PublicAccessBlockConfiguration and a 7-day intermediates lifecycle", () => {
|
|
const t = DEFAULT_TEMPLATE;
|
|
t.resourceCountIs("AWS::S3::Bucket", 1);
|
|
t.hasResourceProperties("AWS::S3::Bucket", {
|
|
PublicAccessBlockConfiguration: {
|
|
BlockPublicAcls: true,
|
|
BlockPublicPolicy: true,
|
|
IgnorePublicAcls: true,
|
|
RestrictPublicBuckets: true,
|
|
},
|
|
LifecycleConfiguration: {
|
|
Rules: [
|
|
{
|
|
Id: "ExpireIntermediates",
|
|
Status: "Enabled",
|
|
Prefix: "renders/",
|
|
ExpirationInDays: 7,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
});
|
|
|
|
it("provisions the three CloudWatch alarms (runaway invocations, Lambda Errors, SFN ExecutionsFailed)", () => {
|
|
const t = DEFAULT_TEMPLATE;
|
|
t.resourceCountIs("AWS::CloudWatch::Alarm", 3);
|
|
t.hasResourceProperties("AWS::CloudWatch::Alarm", {
|
|
MetricName: "Invocations",
|
|
Period: 3600,
|
|
Threshold: 1000,
|
|
});
|
|
t.hasResourceProperties("AWS::CloudWatch::Alarm", {
|
|
MetricName: "Errors",
|
|
Threshold: 1,
|
|
});
|
|
t.hasResourceProperties("AWS::CloudWatch::Alarm", {
|
|
MetricName: "ExecutionsFailed",
|
|
Threshold: 1,
|
|
});
|
|
});
|
|
|
|
// These two synth fresh stacks (non-default props), so they pay the
|
|
// synth cost individually. Bump per-test timeout so a slow CI runner
|
|
// doesn't trip the default 5s.
|
|
it("honours reservedConcurrency when supplied", () => {
|
|
const zipDir = mkdtempSync(join(tmpdir(), "hf-cdk-test-"));
|
|
writeFileSync(join(zipDir, "handler.zip"), "fake");
|
|
const app = new App();
|
|
const stack = new Stack(app, "TestStack");
|
|
new HyperframesRenderStack(stack, "Render", {
|
|
handlerZipPath: join(zipDir, "handler.zip"),
|
|
reservedConcurrency: 4,
|
|
});
|
|
const t = Template.fromStack(stack);
|
|
t.hasResourceProperties("AWS::Lambda::Function", {
|
|
ReservedConcurrentExecutions: 4,
|
|
});
|
|
}, 30000);
|
|
|
|
it("uses the projectName prefix on function + state-machine names", () => {
|
|
const zipDir = mkdtempSync(join(tmpdir(), "hf-cdk-test-"));
|
|
writeFileSync(join(zipDir, "handler.zip"), "fake");
|
|
const app = new App();
|
|
const stack = new Stack(app, "TestStack");
|
|
new HyperframesRenderStack(stack, "Render", {
|
|
handlerZipPath: join(zipDir, "handler.zip"),
|
|
projectName: "demo",
|
|
});
|
|
const t = Template.fromStack(stack);
|
|
t.hasResourceProperties("AWS::Lambda::Function", {
|
|
FunctionName: "demo-render",
|
|
});
|
|
t.hasResourceProperties("AWS::StepFunctions::StateMachine", {
|
|
StateMachineName: "demo-render",
|
|
});
|
|
}, 60000);
|
|
});
|