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

26 lines
No EOL
3.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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.mjs``render.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).