Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions scripts/mirror-vgi-bench-media.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { describe, expect, test } from "bun:test";

import { VGI_BENCH_DEFAULT_REVISION } from "../src/benchmarks/vgi-bench/benchmark";
import { assertFailure, assertSuccess } from "../src/internal/testing";
import type { ManifestEntry } from "./mirror-vgi-bench-media";
import {
candidateSources,
describeReadOptionsError,
extensionOf,
hashManifest,
readOptions,
Expand Down Expand Up @@ -42,7 +44,9 @@ describe("extensionOf", () => {

describe("readOptions", () => {
test("applies defaults", () => {
const options = readOptions([]);
const result = readOptions([]);
assertSuccess(result);
const options = result.success;
expect(options.concurrency).toBe(8);
expect(options.revision).toBe(VGI_BENCH_DEFAULT_REVISION);
expect(options.limit).toBeUndefined();
Expand All @@ -51,15 +55,16 @@ describe("readOptions", () => {
});

test("parses provided flags", () => {
const options = readOptions([
const result = readOptions([
"--concurrency=3",
"--limit=5",
"--out=manifest.json",
"--revision=main",
"--force",
"--dry-run",
]);
expect(options).toEqual({
assertSuccess(result);
expect(result.success).toEqual({
concurrency: 3,
limit: 5,
out: "manifest.json",
Expand All @@ -69,9 +74,41 @@ describe("readOptions", () => {
});
});

test("rejects invalid numeric flags", () => {
expect(() => readOptions(["--concurrency=0"])).toThrow();
expect(() => readOptions(["--limit=abc"])).toThrow();
test("fails with concurrency_not_positive_integer for --concurrency=0", () => {
const result = readOptions(["--concurrency=0"]);
assertFailure(result);
expect(result.failure).toEqual({
kind: "concurrency_not_positive_integer",
});
});

test("fails with limit_not_positive_integer for --limit=abc", () => {
const result = readOptions(["--limit=abc"]);
assertFailure(result);
expect(result.failure).toEqual({ kind: "limit_not_positive_integer" });
});

test("reports the first failing flag when both are invalid", () => {
const result = readOptions(["--concurrency=1.5", "--limit=0"]);
assertFailure(result);
expect(result.failure).toEqual({
kind: "concurrency_not_positive_integer",
});
});
});

describe("describeReadOptionsError", () => {
test.each([
[
{ kind: "concurrency_not_positive_integer" },
"--concurrency must be a positive integer",
],
[
{ kind: "limit_not_positive_integer" },
"--limit must be a positive integer",
],
] as const)("renders %p as the CLI message", (error, message) => {
expect(describeReadOptionsError(error)).toBe(message);
});
});

Expand Down
38 changes: 32 additions & 6 deletions scripts/mirror-vgi-bench-media.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { S3Client } from "bun";
import * as Result from "effect/Result";

import {
VGI_BENCH_CONFIG,
Expand Down Expand Up @@ -88,29 +89,49 @@ type MirrorOutcome =
| { readonly kind: "mirrored"; readonly entry: ManifestEntry }
| { readonly kind: "unresolved"; readonly reason: string };

export function readOptions(argv: readonly string[]): MirrorOptions {
export type ReadOptionsError =
| { readonly kind: "concurrency_not_positive_integer" }
| { readonly kind: "limit_not_positive_integer" };

export function readOptions(
argv: readonly string[]
): Result.Result<MirrorOptions, ReadOptionsError> {
const flag = (name: string): string | undefined => {
const prefixed = `--${name}=`;
const match = argv.find((arg) => arg.startsWith(prefixed));
return match === undefined ? undefined : match.slice(prefixed.length);
};
const concurrency = Number(flag("concurrency") ?? "8");
if (!Number.isInteger(concurrency) || concurrency < 1) {
throw new Error("--concurrency must be a positive integer");
return Result.fail({ kind: "concurrency_not_positive_integer" });
}
const rawLimit = flag("limit");
const limit = rawLimit === undefined ? undefined : Number(rawLimit);
if (limit !== undefined && (!Number.isInteger(limit) || limit < 1)) {
throw new Error("--limit must be a positive integer");
return Result.fail({ kind: "limit_not_positive_integer" });
}
return {
return Result.succeed({
concurrency,
out: flag("out") ?? "vgi-bench-media-manifest.json",
force: argv.includes("--force"),
dryRun: argv.includes("--dry-run"),
revision: flag("revision") ?? VGI_BENCH_DEFAULT_REVISION,
limit,
};
});
}

export function describeReadOptionsError(error: ReadOptionsError): string {
switch (error.kind) {
case "concurrency_not_positive_integer": {
return "--concurrency must be a positive integer";
}
case "limit_not_positive_integer": {
return "--limit must be a positive integer";
}
default: {
return error satisfies never;
}
}
}

export type { ManifestEntry };
Expand Down Expand Up @@ -238,7 +259,12 @@ export function hashManifest(entries: readonly ManifestEntry[]): string {

async function main(): Promise<void> {
const env = readMediaMirrorEnv();
const options = readOptions(process.argv.slice(2));
const parsed = readOptions(process.argv.slice(2));
if (Result.isFailure(parsed)) {
process.stderr.write(`${describeReadOptionsError(parsed.failure)}\n`);
process.exit(1);
}
const options = parsed.success;
const s3 = new S3Client(env);
const allVideos = await fetchSourceVideos(
options.revision,
Expand Down
Loading