Files
hyperframes/packages/gcp-cloud-run/src/sdk/renderToCloudRun.test.ts
T
James Russo 17a2a00ed5 feat(cloud): default distributed plans to v2 (#3311)
* feat(cloud): default distributed plans to v2

* fix(cloud): address plan v2 review feedback

* fix(examples): document explicit v2 samples
2026-08-17 17:24:31 -04:00

155 lines
5.1 KiB
TypeScript

/**
* `renderToCloudRun` unit tests — argument assembly, required-field
* validation, and the CreateExecution call over a fake ExecutionsClient.
*/
import { describe, expect, it } from "bun:test";
import type { SerializableDistributedRenderConfig } from "../events.js";
import { type ExecutionsClientLike, renderToCloudRun } from "./renderToCloudRun.js";
import type { SiteHandle } from "./deploySite.js";
const config = {
fps: 30,
width: 1920,
height: 1080,
format: "mp4",
} as SerializableDistributedRenderConfig;
const site: SiteHandle = {
siteId: "abc",
bucketName: "b",
projectGcsUri: "gs://b/sites/abc/project.tar.gz",
bytes: 100,
uploadedAt: "2026-06-06T00:00:00Z",
uploaded: true,
};
class FakeExecutions implements ExecutionsClientLike {
lastArgument: string | null = null;
lastParent: string | null = null;
workflowPath(project: string, location: string, workflow: string): string {
return `projects/${project}/locations/${location}/workflows/${workflow}`;
}
async createExecution(req: {
parent: string;
execution: { argument: string };
}): Promise<[{ name?: string | null; state?: string | null }]> {
this.lastParent = req.parent;
this.lastArgument = req.execution.argument;
return [{ name: `${req.parent}/executions/exec-123`, state: "ACTIVE" }];
}
}
function opts(executions: ExecutionsClientLike) {
return {
siteHandle: site,
config,
bucketName: "b",
projectId: "proj",
location: "us-central1",
workflowId: "hyperframes-render",
serviceUrl: "https://render-abc.run.app",
renderId: "hf-render-fixed",
executions,
};
}
describe("renderToCloudRun", () => {
it("starts an execution and returns a handle", async () => {
const fake = new FakeExecutions();
const handle = await renderToCloudRun(opts(fake));
expect(handle.renderId).toBe("hf-render-fixed");
expect(handle.executionName).toBe(
"projects/proj/locations/us-central1/workflows/hyperframes-render/executions/exec-123",
);
expect(handle.outputGcsUri).toBe("gs://b/renders/hf-render-fixed/output.mp4");
expect(handle.projectGcsUri).toBe("gs://b/sites/abc/project.tar.gz");
expect(Object.keys(handle)).toEqual([
"renderId",
"executionName",
"bucketName",
"workflowId",
"outputGcsUri",
"projectGcsUri",
"startedAt",
]);
});
it("builds the workflow argument the YAML expects", async () => {
const fake = new FakeExecutions();
await renderToCloudRun(opts(fake));
const arg = JSON.parse(fake.lastArgument ?? "{}");
expect(arg).toEqual({
RenderId: "hf-render-fixed",
ProjectGcsUri: "gs://b/sites/abc/project.tar.gz",
PlanOutputGcsPrefix: "gs://b/renders/hf-render-fixed/",
OutputGcsUri: "gs://b/renders/hf-render-fixed/output.mp4",
ServiceUrl: "https://render-abc.run.app",
Config: config,
PlanProtocol: "v2",
});
expect(fake.lastParent).toBe(
"projects/proj/locations/us-central1/workflows/hyperframes-render",
);
});
it("preserves explicit plan protocol v1 compatibility", async () => {
const fake = new FakeExecutions();
await renderToCloudRun({ ...opts(fake), planProtocol: "v1" });
const arg = JSON.parse(fake.lastArgument ?? "{}");
expect(arg).toEqual({
RenderId: "hf-render-fixed",
ProjectGcsUri: "gs://b/sites/abc/project.tar.gz",
PlanOutputGcsPrefix: "gs://b/renders/hf-render-fixed/",
OutputGcsUri: "gs://b/renders/hf-render-fixed/output.mp4",
ServiceUrl: "https://render-abc.run.app",
Config: config,
PlanProtocol: "v1",
});
});
it("derives the output extension from the format", async () => {
const fake = new FakeExecutions();
const handle = await renderToCloudRun({
...opts(fake),
config: { ...config, format: "webm" } as SerializableDistributedRenderConfig,
});
expect(handle.outputGcsUri).toBe("gs://b/renders/hf-render-fixed/output.webm");
});
it("requires serviceUrl", async () => {
const fake = new FakeExecutions();
await expect(renderToCloudRun({ ...opts(fake), serviceUrl: "" })).rejects.toThrow(
/serviceUrl is required/,
);
});
it("requires a siteHandle or projectDir", async () => {
const fake = new FakeExecutions();
const { siteHandle, ...rest } = opts(fake);
void siteHandle;
await expect(renderToCloudRun(rest)).rejects.toThrow(/siteHandle or projectDir/);
});
it("validates the config before any GCP call", async () => {
const fake = new FakeExecutions();
await expect(
renderToCloudRun({ ...opts(fake), config: { ...config, fps: 25 } as never }),
).rejects.toThrow(/config\.fps/);
expect(fake.lastArgument).toBeNull();
});
it("rejects a renderId that could escape the GCS key prefix", async () => {
const fake = new FakeExecutions();
await expect(renderToCloudRun({ ...opts(fake), renderId: "../escape" })).rejects.toThrow(
/renderId must match/,
);
await expect(renderToCloudRun({ ...opts(fake), renderId: "has/slash" })).rejects.toThrow(
/renderId must match/,
);
expect(fake.lastArgument).toBeNull();
});
});