Tests pin each window refusal: a negative first, first equal to last, a fractional last, extra or misnamed --frames arguments

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-25 18:32:27 +01:00
commit bdee73c028
3 changed files with 18 additions and 35 deletions

View file

@ -1,7 +1,7 @@
// Stands in for kimodo-resident-worker.py in the daemon's tests. It binds port 0, prints the ready line the
// daemon waits for, and answers /health and /generate with what the daemon gave it. The --model value picks a
// misbehaviour: crash-before-ready, hang-before-ready, sick, slow-health, stubborn, fail-generate,
// refuse-generate, drop-generate, slow-generate, writer (appends to <output>.writes every 50 ms, never answers, ignores SIGTERM), slow-to-stop (no answer; prints a line and exits 1.5 s after SIGTERM), chatty (prints a line the moment it is healthy), encoder (a grandchild, then no answer), graceful (exits 0.5 s after SIGTERM), die-after-ready, bvh-outside (lists a BVH outside the job's directory), bvh-link (lists a symlink as its BVH), bvh-fifo (lists a FIFO as its BVH), plant-link (a normal answer with a file symlink and a directory symlink planted beside the BVH), no-loops (a normal answer that leaves out the loops a loop request asked for), bad-loops (loops whose window is not a frame range), short-loops (one window fewer than samples). A loop request is answered with loops, sample k as {first 3 + k, last 223 + k}. A request with bvh writes <output>.bvh (motion/motion_NN.bvh for several samples) and lists it. Any other value is just the model the worker serves.
// refuse-generate, drop-generate, slow-generate, writer (appends to <output>.writes every 50 ms, never answers, ignores SIGTERM), slow-to-stop (no answer; prints a line and exits 1.5 s after SIGTERM), chatty (prints a line the moment it is healthy), encoder (a grandchild, then no answer), graceful (exits 0.5 s after SIGTERM), die-after-ready, bvh-outside (lists a BVH outside the job's directory), bvh-link (lists a symlink as its BVH), bvh-fifo (lists a FIFO as its BVH), plant-link (a normal answer with a file symlink and a directory symlink planted beside the BVH), no-loops (a normal answer that leaves out the loops a loop request asked for), bad-loops, negative-loops, empty-loops, fractional-last-loops (loops whose window is not a frame range: a fractional first, a negative first, first equal to last, a fractional last), short-loops (one window fewer than samples). A loop request is answered with loops, sample k as {first 3 + k, last 223 + k}. A request with bvh writes <output>.bvh (motion/motion_NN.bvh for several samples) and lists it. Any other value is just the model the worker serves.
import http from "node:http";
import os from "node:os";
import path from "node:path";
@ -14,6 +14,12 @@ const flag = (name) => {
return index < 0 ? undefined : argv[index + 1];
};
const model = flag("--model");
const BAD_WINDOWS = {
"bad-loops": { first: 5.5, last: 9 },
"negative-loops": { first: -1, last: 9 },
"empty-loops": { first: 7, last: 7 },
"fractional-last-loops": { first: 5, last: 9.5 },
};
const spawnLog = path.join(process.env.VILI_EMBEDDINGS_DIR, "stub-spawns.log");
let requests = 0;
let healthCalls = 0;
@ -118,9 +124,8 @@ if (model === "hang-before-ready") {
metaSeed: payload.meta?.seed,
bvh: payload.bvh,
...(payload.loop && model !== "no-loops" ? {
loops: Array.from({ length: payload.numSamples - (model === "short-loops" ? 1 : 0) }, (_, k) => (model === "bad-loops"
? { first: 5.5, last: 9, poseCost: 0, velocityCost: 0 }
: { first: 3 + k, last: 223 + k, poseCost: 0.03, velocityCost: 0.2 })),
loops: Array.from({ length: payload.numSamples - (model === "short-loops" ? 1 : 0) }, (_, k) => (BAD_WINDOWS[model]
?? { first: 3 + k, last: 223 + k, poseCost: 0.03, velocityCost: 0.2 })),
} : {}),
bvhStandardTpose: payload.bvhStandardTpose,
model: model || "stub-model",

View file

@ -1480,30 +1480,6 @@ test("loop asks for the seamless window, and the window is the FBX's frame range
}
});
test("constraints given twice are refused before anything is written or spawned", async () => {
const daemon = await startDaemon();
try {
const inline = [{ type: "root2d" }];
for (const bad of [
{ constraints: inline, constraints_path: "/canary/a.json" },
{ constraints: inline, constraintsPath: "/canary/a.json" },
{ constraints: "/canary/a.json", constraints_path: "/canary/b.json" },
{ constraints_path: "/canary/a.json", constraintsPath: "/canary/b.json" },
]) {
const answer = await generate(daemon, exportRequest(bad));
assert.equal(answer.status, 400, JSON.stringify(bad));
assert.deepEqual(answer.body, { ok: false, error: "Invalid constraints request." });
assert.ok(!answer.raw.includes("canary"), "the refusal repeated the input");
}
assert.equal(existsSync(path.join(daemon.stateRoot, "artifacts")), false, "no artifact directory was made");
assert.deepEqual(jobFiles(daemon), []);
assert.deepEqual(daemon.spawns(), [], "no worker was started");
assert.equal((await generate(daemon, exportRequest({ constraints_path: "/some/where.json" }))).status, 200, "one input is fine");
} finally {
await daemon.stop();
}
});
test("past 100 samples each clip is exported over the window of its own sample", async () => {
const daemon = await startDaemon();
try {
@ -1568,7 +1544,7 @@ test("loop is a boolean and needs fbx, refused before anything is written or spa
});
test("a loop request whose answer has no usable window for a sample fails without exporting that sample", async () => {
for (const [model, exported] of [["no-loops", 0], ["bad-loops", 0], ["short-loops", 1]]) {
for (const [model, exported] of [["no-loops", 0], ["bad-loops", 0], ["negative-loops", 0], ["empty-loops", 0], ["fractional-last-loops", 0], ["short-loops", 1]]) {
const daemon = await startDaemon();
try {
const answer = await generate(daemon, exportRequest({ model, loop: true, numSamples: 2 }));

View file

@ -242,14 +242,16 @@ class BvhToFbx(unittest.TestCase):
def test_frames_outside_the_take_or_malformed_exit_without_a_file(self):
bvh = self.walk("short", 31)
for index, (frames, exit_code) in enumerate((
(("0", "10"), 4), (("5", "32"), 4), (("10", "10"), 4), (("20", "10"), 4),
(("5",), 3), (("a", "9"), 3), (("-1", "9"), 3),
for index, (arguments, exit_code) in enumerate((
(("--frames", "0", "10"), 4), (("--frames", "5", "32"), 4), (("--frames", "10", "10"), 4),
(("--frames", "20", "10"), 4),
(("--frames", "5"), 3), (("--frames", "a", "9"), 3), (("--frames", "-1", "9"), 3),
(("--frames", "4", "20", "9"), 3), (("--range", "4", "20"), 3), (("4", "20"), 3),
)):
fbx = self.dir / f"refused{index}.fbx"
run = blender("--python", str(SCRIPT), "--", str(bvh), str(fbx), "refused", "--frames", *frames)
self.assertEqual(run.returncode, exit_code, frames)
self.assertFalse(fbx.exists(), frames)
run = blender("--python", str(SCRIPT), "--", str(bvh), str(fbx), "refused", *arguments)
self.assertEqual(run.returncode, exit_code, arguments)
self.assertFalse(fbx.exists(), arguments)
if __name__ == "__main__":