refactor(main): execFileAsync helper — unify the 5 spawn-and-read sites
Replace the hand-rolled `new Promise((resolve) => execFile(…, cb))` wrappers in
probe / ytdlp (×2) / ffmpeg / indexer.probeFlat / download.probeMeta with one
lib/exec.ts execFileAsync returning a normalized
{ok,stdout,stderr,timedOut,error} that never rejects. Each caller keeps its own
error mapping (timedOut -> "Timed out …" vs stderr) and JSON parsing; behaviour
is unchanged. windowsHide defaults on; per-call timeout/maxBuffer preserved.
Foundation for CC4/CC5 — the stdout line-buffer half lands with SIMP5, the
net.request half with SIMP16, at which point those checkboxes close.
Unit-tested (exec.test.ts) against the node binary: ok / stderr+nonzero-exit /
missing-binary / timeout. typecheck + 262 tests + eslint + prettier green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { execFileAsync } from '../src/main/lib/exec'
|
||||
|
||||
// Exercised against the Node binary itself so the test needs no fixtures and is
|
||||
// deterministic. Covers the contract the six migrated spawn sites rely on
|
||||
// (SIMP2/CC4/CC5): normalized ok/stdout/stderr, never-rejects, and the timedOut flag.
|
||||
describe('execFileAsync (SIMP2/CC4/CC5)', () => {
|
||||
it('resolves ok with stdout on a clean exit', async () => {
|
||||
const r = await execFileAsync(process.execPath, ['-e', 'process.stdout.write("hello")'])
|
||||
expect(r.ok).toBe(true)
|
||||
expect(r.stdout).toBe('hello')
|
||||
expect(r.timedOut).toBe(false)
|
||||
expect(r.error).toBeUndefined()
|
||||
})
|
||||
|
||||
it('captures stderr and reports not-ok on a non-zero exit', async () => {
|
||||
const r = await execFileAsync(process.execPath, [
|
||||
'-e',
|
||||
'process.stderr.write("boom"); process.exit(2)'
|
||||
])
|
||||
expect(r.ok).toBe(false)
|
||||
expect(r.stderr).toContain('boom')
|
||||
expect(r.error).toBeInstanceOf(Error)
|
||||
expect(r.timedOut).toBe(false)
|
||||
})
|
||||
|
||||
it('never rejects — a missing binary resolves not-ok with an error', async () => {
|
||||
const r = await execFileAsync('definitely-not-a-real-binary-xyz', ['--version'])
|
||||
expect(r.ok).toBe(false)
|
||||
expect(r.error).toBeDefined()
|
||||
expect(r.timedOut).toBe(false)
|
||||
})
|
||||
|
||||
it('flags timedOut when the timeout kills the process', async () => {
|
||||
const r = await execFileAsync(process.execPath, ['-e', 'setTimeout(() => {}, 5000)'], {
|
||||
timeout: 100
|
||||
})
|
||||
expect(r.ok).toBe(false)
|
||||
expect(r.timedOut).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user