ingest.test.js 4.07 KB
// Regression for a real incident (2026-09-02): syncLibrary()'s rebuild path
// only carried `likes` forward from the old record, silently resetting
// playCount/lastPlayedAt to "never played" on every periodic sync (every
// 5 min in server.js) for any clip that hadn't been touched in admin.html
// (i.e. wasn't `edited: true`). Run: node --test ingest.test.js
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const os = require("node:os");
const http = require("node:http");

function startMockH3(jobs) {
  return new Promise((resolve) => {
    const server = http.createServer((req, res) => {
      if (req.method === "GET" && req.url.startsWith("/v1/videos")) {
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ jobs }));
        return;
      }
      res.writeHead(404);
      res.end();
    });
    server.listen(0, () => resolve(server));
  });
}

test("syncLibrary: carries playCount/lastPlayedAt forward for non-edited clips, not just likes", async () => {
  const job = {
    id: "clip-1",
    status: "done",
    download: true,
    created_at: 1700000000,
    partition: "text",
    req: { prompt: "a long enough real prompt that will not match the isTestJob short-circuit ".repeat(3), width: 480, height: 832, frames: 240 },
  };
  const mockH3 = await startMockH3([job]);
  const mockH3Port = mockH3.address().port;

  const cwd = fs.mkdtempSync(path.join(os.tmpdir(), "ingest-test-"));
  fs.writeFileSync(
    path.join(cwd, "library.json"),
    JSON.stringify([{ id: "clip-1", source: "h3console", prompt: "old", fullPrompt: "old", edited: false, width: 480, height: 832, duration: 10, partition: "text", likes: 3, createdAt: 1000, lastPlayedAt: 123456, playCount: 7 }])
  );
  fs.copyFileSync(path.join(__dirname, "ingest.js"), path.join(cwd, "ingest.js"));

  process.env.H3_CONSOLE_BASE = `http://localhost:${mockH3Port}`;
  process.env.H3_CONSOLE_TOKEN = "mock-token";
  delete require.cache[path.join(cwd, "ingest.js")];
  const { syncLibrary } = require(path.join(cwd, "ingest.js"));

  const cwdBefore = process.cwd();
  process.chdir(cwd);
  try {
    await syncLibrary();
  } finally {
    process.chdir(cwdBefore);
    mockH3.close();
  }

  const library = JSON.parse(fs.readFileSync(path.join(cwd, "library.json"), "utf8"));
  const clip = library.find((c) => c.id === "clip-1");
  assert.equal(clip.likes, 3, "likes was already carried forward correctly");
  assert.equal(clip.lastPlayedAt, 123456, "lastPlayedAt must survive a sync, not reset to unplayed");
  assert.equal(clip.playCount, 7, "playCount must survive a sync, not reset to 0");

  fs.rmSync(cwd, { recursive: true, force: true });
});

test("syncLibrary: a never-played clip stays without playCount/lastPlayedAt fields (no false '0 plays')", async () => {
  const job = {
    id: "clip-2",
    status: "done",
    download: true,
    created_at: 1700000000,
    partition: "text",
    req: { prompt: "a long enough real prompt that will not match the isTestJob short-circuit ".repeat(3), width: 480, height: 832, frames: 240 },
  };
  const mockH3 = await startMockH3([job]);
  const mockH3Port = mockH3.address().port;

  const cwd = fs.mkdtempSync(path.join(os.tmpdir(), "ingest-test-"));
  fs.writeFileSync(path.join(cwd, "library.json"), JSON.stringify([]));
  fs.copyFileSync(path.join(__dirname, "ingest.js"), path.join(cwd, "ingest.js"));

  process.env.H3_CONSOLE_BASE = `http://localhost:${mockH3Port}`;
  process.env.H3_CONSOLE_TOKEN = "mock-token";
  delete require.cache[path.join(cwd, "ingest.js")];
  const { syncLibrary } = require(path.join(cwd, "ingest.js"));

  const cwdBefore = process.cwd();
  process.chdir(cwd);
  try {
    await syncLibrary();
  } finally {
    process.chdir(cwdBefore);
    mockH3.close();
  }

  const library = JSON.parse(fs.readFileSync(path.join(cwd, "library.json"), "utf8"));
  const clip = library.find((c) => c.id === "clip-2");
  assert.equal("lastPlayedAt" in clip, false);
  assert.equal("playCount" in clip, false);

  fs.rmSync(cwd, { recursive: true, force: true });
});