mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 16:42:27 +00:00
* feat(cloud): default distributed plans to v2 * fix(cloud): address plan v2 review feedback * fix(examples): document explicit v2 samples
155 lines
5.1 KiB
TypeScript
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();
|
|
});
|
|
});
|