run-paths.test.mjs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import assert from "node:assert/strict";
  2. import { randomUUID } from "node:crypto";
  3. import { rm } from "node:fs/promises";
  4. import { join } from "node:path";
  5. import test from "node:test";
  6. import {
  7. assertCanonicalRunDirectory,
  8. assertRunFile,
  9. createRun,
  10. createRunId,
  11. pathsForRun,
  12. requestIndexDirectory,
  13. runsRoot,
  14. } from "./run-paths.mjs";
  15. test("run IDs and paths always resolve below the project run root", () => {
  16. const runId = createRunId(new Date("2026-07-23T12:34:56.000Z"), "abcdef");
  17. assert.equal(runId, "run-20260723203456-abcdef");
  18. const paths = pathsForRun(runId);
  19. assert.equal(paths.run_directory, join(runsRoot, runId));
  20. assert.equal(paths.runs_root, join(paths.project_root, "生成结果", "电商七图"));
  21. assert.equal(paths.attachments_directory, join(runsRoot, runId, "商品附件"));
  22. assert.equal(paths.images_directory, join(runsRoot, runId, "成品图"));
  23. });
  24. test("run IDs use Asia/Shanghai calendar dates across the UTC midnight boundary", () => {
  25. const runId = createRunId(new Date("2026-07-23T16:55:04.000Z"), "123abc");
  26. assert.equal(runId, "run-20260724005504-123abc");
  27. });
  28. test("run path checks reject skill-source and nested output directories", () => {
  29. assert.throws(
  30. () => assertCanonicalRunDirectory(join(runsRoot, "run-ok", "nested")),
  31. /RUN_PATH_INVALID/,
  32. );
  33. const runDirectory = join(runsRoot, "run-20260723123456-abcdef");
  34. assert.throws(
  35. () => assertRunFile(join(runDirectory, "nested", "jimeng-result.json"), runDirectory),
  36. /RUN_PATH_INVALID/,
  37. );
  38. });
  39. test("Windows run path checks ignore drive-letter casing", { skip: process.platform !== "win32" }, () => {
  40. const runDirectory = join(runsRoot, "run-20260723123456-abcdef");
  41. const lowerCaseDrive = `${runDirectory[0].toLowerCase()}${runDirectory.slice(1)}`;
  42. assert.equal(assertCanonicalRunDirectory(lowerCaseDrive).toLowerCase(), runDirectory.toLowerCase());
  43. assert.equal(
  44. assertRunFile(join(lowerCaseDrive, "vision-result.json"), lowerCaseDrive, "vision-result.json").toLowerCase(),
  45. join(runDirectory, "vision-result.json").toLowerCase(),
  46. );
  47. });
  48. test("the same Claude request key always reuses one run directory", async () => {
  49. const requestKey = `test-request-${randomUUID()}`;
  50. const indexDirectory = requestIndexDirectory(requestKey);
  51. let first;
  52. try {
  53. first = await createRun({ requestKey });
  54. const second = await createRun({ requestKey });
  55. assert.equal(first.reused_existing_run, false);
  56. assert.equal(second.reused_existing_run, true);
  57. assert.equal(second.run_id, first.run_id);
  58. assert.equal(second.run_directory, first.run_directory);
  59. } finally {
  60. if (first) await rm(first.run_directory, { recursive: true, force: true });
  61. await rm(indexDirectory, { recursive: true, force: true });
  62. }
  63. });