Files
hyperframes/packages/cli/src/commands/lambda/render.test.ts
T
Miguel Ángel 54d0af57eb feat(engine): render sets a keyframe interval and a peak bitrate cap (#6444)
* feat(engine): encoders cap peak bitrate and place keyframes on a set interval

* style(engine): shorten the rate-cap comment

* style(engine): drop the doc lines the comment ratchet flagged

* feat(producer): mp4 renders honour a keyframe interval and a peak bitrate cap on every encoder path

* style(producer): shorten the delivery encoder file headers

* style(producer): drop a comment line from the segment manifest

* style(producer): shorten the integration test header

* test: delivery encoder tests follow the ffprobe argv contract and run in the integration lane

* feat: the render request, server and Lambda plan carry the keyframe interval and peak bitrate cap

* fix(studio): the Studio render route passes the keyframe interval and bitrate cap to the encoder

* chore(studio-server): drop a comment the helper's name already says

* feat(cli): render and lambda render take --keyframe-interval, --max-bitrate and --buffer-size
2026-10-27 00:29:06 +00:00

89 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Boundary tests for the wire config emitted by `hyperframes lambda render`.
* Pins that the aspect-agnostic resolution flag survives all the way into
* `SerializableDistributedRenderConfig`, which is what the Lambda worker's
* compile stage reads before remapping `landscape` → `portrait` for an
* aspect-agnostic alias like `--output-resolution 1080p`.
*
* See `../cloudrun.test.ts` for the parseOutputResolution counterpart and
* `../render.test.ts` for the local-CLI preflight guardrails.
*/
import { describe, expect, it } from "vitest";
import lambdaCommand from "../lambda.js";
import { buildLambdaRenderConfig, type RenderArgs } from "./render.js";
const BASE_ARGS: RenderArgs = {
projectDir: "/tmp/hf-project",
stackName: "hf-test",
fps: 30,
width: 1080,
height: 1920,
format: "mp4",
json: false,
wait: false,
waitIntervalMs: 5000,
};
describe("buildLambdaRenderConfig — aspect-agnostic wire threading", () => {
it("threads outputResolutionAspectAgnostic=true through for portrait 1080p", () => {
// The exact bug shape: portrait 1080×1920 comp + `--output-resolution 1080p`.
// Before the fix, the aspect-agnostic flag never reached the wire, so
// the Lambda worker saw the explicit `landscape` preset and rejected
// the portrait comp — reproducing the local-CLI regression on the
// distributed path.
const config = buildLambdaRenderConfig(
{ ...BASE_ARGS, outputResolution: "landscape", outputResolutionAspectAgnostic: true },
undefined,
);
expect(config.outputResolution).toBe("landscape");
expect(config.outputResolutionAspectAgnostic).toBe(true);
});
it("keeps the aspect-agnostic key absent when the flag is a canonical preset", () => {
// Sparse-wire invariant: only forward `true`; canonical presets stay
// strict and don't need the compile-stage remap.
const config = buildLambdaRenderConfig(
{ ...BASE_ARGS, outputResolution: "portrait-4k" },
undefined,
);
expect(config.outputResolution).toBe("portrait-4k");
expect(config.outputResolutionAspectAgnostic).toBeUndefined();
});
it("sends the delivery options on the wire and nothing when they are unset", () => {
const config = buildLambdaRenderConfig(
{ ...BASE_ARGS, keyframeIntervalSeconds: 2, maxBitrate: "8M", bufferSize: "12M" },
undefined,
);
expect(config).toMatchObject({
keyframeIntervalSeconds: 2,
maxBitrate: "8M",
bufferSize: "12M",
});
expect(
JSON.parse(JSON.stringify(buildLambdaRenderConfig(BASE_ARGS, undefined))),
).not.toHaveProperty("maxBitrate");
});
it("carries variables verbatim through the wire config", () => {
const config = buildLambdaRenderConfig(BASE_ARGS, { alice: "hello" });
expect(config.variables).toEqual({ alice: "hello" });
});
});
describe("lambda render chunk sizing", () => {
it("hands the deploy's reserved concurrency to the planner", () => {
expect(buildLambdaRenderConfig(BASE_ARGS, undefined, 64).workerConcurrency).toBe(64);
expect(buildLambdaRenderConfig(BASE_ARGS, undefined).workerConcurrency).toBeUndefined();
});
it("help no longer claims --chunk-size defaults to 240", () => {
const chunkSizeArg = lambdaCommand.args
? Reflect.get(lambdaCommand.args, "chunk-size")
: undefined;
expect(chunkSizeArg?.description).not.toContain("240");
expect(chunkSizeArg?.description).toContain("timeout");
});
});