opencode-config/docs/handoff/pr-184-draw-image-test-helper-input-svg-race.md
Sergey 8c00346b76
fix(draw-image): per-process temp dir in renderToPng test helpers (#184)
* fix(draw-image): per-process temp dir in renderToPng test helpers

* docs(handoff): add handoff and ADR for renderToPng temp dir fix

* docs(project-map): note per-process temp dir fix in renderToPng helpers

* docs(handoff): set PR number

* docs(handoff): replace PR number placeholder in frontmatter

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-31 22:28:04 +03:00

3.9 KiB
Raw Permalink Blame History


pr: 184 title: fix(draw-image): per-process temp dir in renderToPng test helpers

Что сделано

  • tests/render.integration.test.ts: хелпер renderToPng переписан — вместо общего path.join(TMP, "input.svg") (где TMP = "/tmp/draw-image-integration" — общий для всех параллельных vitest-процессов) используется уникальный temp-каталог на каждый вызов через mkdtempSync(path.join(os.tmpdir(), \draw-image-test-${process.pid}-`)), внутри которого пишется input.svg`.
  • tests/render.integration.test.ts: добавлен finally-блок с rmSync(tmpDir, { recursive: true, force: true }) — temp-каталог удаляется после рендера даже при ошибке/exit.
  • tests/render.integration.test.ts: импорты очищены — require("node:fs") заменён на статический writeFileSync/mkdtempSync из node:fs, добавлен import os from "node:os".
  • tests/render.optional.integration.test.ts: аналогичный фикс хелпера renderToPng (тот же паттерн TMP/input.svg) — уникальный temp-каталог через mkdtempSync с PID + cleanup в finally.

Почему

Тестовый хелпер renderToPng в обоих integration-тестах писал временный SVG в жёстко заданный path.join(TMP, "input.svg") где TMP — общий каталог для всех параллельных vitest-процессов. При параллельном запуске (CI матрица, npx vitest run × N в параллель, несколько vitest-воркеров) процессы конкурировали за один input.svg: один процесс обнулял/перезаписывал файл через writeFileSync, пока другой его читал через render.mjsrender.mjs падал с Input Buffer is empty. Это аналогично багу #160 (продакшн cli.ts), но в тестовом хелпере. Уникальный temp-каталог на вызов (mkdtempSync с PID в префиксе) + cleanup в finally устраняют race и гарантированно удаляют leftover. mkdtempSync выбран вместо PID-суффикса на файл, т.к. решает и race между процессами, и между threads одного процесса (каждый вызов renderToPng = свой уникальный каталог).

Pending

Watch out

  • Баг вне scope (создан issue #183): при верификации параллельным запуском 10× npx vitest run обнаружен отдельный race на общих output-каталогах beforeAll (/tmp/draw-image-integration, /tmp/draw-image-cleanup, /tmp/draw-image-idempotency и т.д.) — beforeAll делает rmSync(TMP, recursive) и процесс удаляет output PNG другого процесса → existsSync(outPath) = false / idempotency skipped вместо rendered / unable to open for write. Этот race НЕ связан с input.svg/Input Buffer is empty и чинится отдельно в #183. Критерий приёмки #177 выполнен: Input Buffer is empty полностью устранён во всех 10 параллельных прогонах.
  • Одиночный прогон ×10 стабильно зелёный (58/58 каждый прогон) — проверено последовательно.
  • render.mjs не изменён (контракт «принимает path к SVG как argv» сохранён).
  • Продакшн-код cli.ts не тронут (исправлен в #160).