51 lines
2.4 KiB
TypeScript
51 lines
2.4 KiB
TypeScript
import test from "node:test";
|
|||
|
|
import assert from "node:assert/strict";
|
||
|
|
import { mkdtemp, writeFile, symlink, rm } from "node:fs/promises";
|
||
|
|
import { join } from "node:path";
|
||
|
|
import { tmpdir } from "node:os";
|
||
|
|
import { CandidateMetadataBudget, readCandidateMetadata } from "../src/execution-world/metadata.js";
|
||
|
|
|
||
|
|
test("concurrent candidate reservations enforce aggregate and owner limits and release exactly once", () => {
|
||
|
|
const budget = new CandidateMetadataBudget({ bytes: 1000, ownerBytes: 600, candidates: 3 });
|
||
|
|
const first = budget.acquire("a"),
|
||
|
|
second = budget.acquire("a"),
|
||
|
|
third = budget.acquire("b");
|
||
|
|
assert.throws(() => budget.acquire("c"), /CANDIDATE_METADATA_LIMIT/);
|
||
|
|
first.charge(400);
|
||
|
|
second.charge(200);
|
||
|
|
third.charge(400);
|
||
|
|
assert.throws(() => second.charge(1), /CANDIDATE_METADATA_LIMIT/);
|
||
|
|
assert.throws(() => third.charge(1), /CANDIDATE_METADATA_LIMIT/);
|
||
|
|
assert.equal(budget.snapshot().bytes, 1000);
|
||
|
|
second.release();
|
||
|
|
second.release();
|
||
|
|
assert.equal(budget.snapshot().bytes, 800);
|
||
|
|
assert.throws(() => second.charge(1), /CANDIDATE_METADATA_CLOSED/);
|
||
|
|
first.release();
|
||
|
|
third.release();
|
||
|
|
assert.deepEqual(budget.snapshot(), { bytes: 0, candidates: 0, owners: 0, limits: budget.limits });
|
||
|
|
});
|
||
|
|
|
||
|
|
test("metadata files reserve parse/index space before allocation and refuse oversized or linked inputs", async () => {
|
||
|
|
const root = await mkdtemp(join(tmpdir(), "qx-metadata-budget-"));
|
||
|
|
const budget = new CandidateMetadataBudget({ bytes: 512, ownerBytes: 512, candidates: 2 });
|
||
|
|
const scope = budget.acquire("workspace");
|
||
|
|
try {
|
||
|
|
const file = join(root, "metadata.json");
|
||
|
|
await writeFile(file, '{"ok":true}');
|
||
|
|
assert.equal(new TextDecoder().decode(await readCandidateMetadata(file, scope, 100)), '{"ok":true}');
|
||
|
|
assert.equal(scope.bytes, 12 * 32);
|
||
|
|
await assert.rejects(readCandidateMetadata(file, scope, 100), /CANDIDATE_METADATA_LIMIT/);
|
||
|
|
assert.equal(scope.bytes, 12 * 32);
|
||
|
|
await assert.rejects(readCandidateMetadata(file, scope, 5), /CANDIDATE_METADATA_FILE_LIMIT/);
|
||
|
|
await symlink(file, join(root, "linked"));
|
||
|
|
await assert.rejects(readCandidateMetadata(join(root, "linked"), scope, 100), { code: "ELOOP" });
|
||
|
|
await assert.rejects(readCandidateMetadata(root, scope, 100), /CANDIDATE_METADATA_FILE_LIMIT/);
|
||
|
|
assert.equal(scope.bytes, 12 * 32);
|
||
|
|
} finally {
|
||
|
|
scope.release();
|
||
|
|
await rm(root, { recursive: true, force: true });
|
||
|
|
}
|
||
|
|
assert.equal(budget.snapshot().bytes, 0);
|
||
|
|
});
|