d18ada4ee7
Docker Publish / docker (web, apps/web/Dockerfile, web) (push) Failing after 0s
Docker Publish / docker (api, apps/api/Dockerfile, api) (push) Failing after 1s
Publish Extension / detect-version (push) Has been skipped
Publish Extension / submit (push) Has been cancelled
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
|
|
import { MemoryPersistAdapter } from '../src/persist'
|
|
import { ProcessRegistry } from '../src/process'
|
|
|
|
describe('ProcessRegistry', () => {
|
|
it('records spawn + close pairs in the journal', async () => {
|
|
const persist = new MemoryPersistAdapter()
|
|
const reg = new ProcessRegistry({ persist, kill: vi.fn(), sleep: async () => {} })
|
|
await reg.recordSpawn({
|
|
taskId: 't',
|
|
attemptId: 'a',
|
|
pid: 100,
|
|
pidStartedAt: 50,
|
|
kind: 'yt-dlp',
|
|
spawnedAt: Date.now()
|
|
})
|
|
await reg.recordClose('t', 'a', 0, null)
|
|
const journal = persist.journalSnapshot()
|
|
expect(journal.map((r) => r.op)).toEqual(['spawn', 'close'])
|
|
const open = await persist.findOpenSpawns()
|
|
expect(open).toHaveLength(0)
|
|
})
|
|
|
|
it('cancel issues SIGTERM then SIGKILL after grace', async () => {
|
|
const persist = new MemoryPersistAdapter()
|
|
const kill = vi.fn()
|
|
const reg = new ProcessRegistry({
|
|
persist,
|
|
kill,
|
|
sleep: async () => {},
|
|
// Simulate the process never dying so SIGKILL fires.
|
|
killGracePeriodMs: 0
|
|
})
|
|
await reg.recordSpawn({
|
|
taskId: 't',
|
|
attemptId: 'a',
|
|
pid: 100,
|
|
pidStartedAt: 50,
|
|
kind: 'yt-dlp',
|
|
spawnedAt: Date.now()
|
|
})
|
|
await reg.cancel('t', 'a')
|
|
expect(kill).toHaveBeenCalledWith(100, 'SIGTERM')
|
|
// killed row written
|
|
const journal = persist.journalSnapshot()
|
|
expect(journal.map((r) => r.op)).toContain('killed')
|
|
})
|
|
|
|
it('reconcile finds spawn rows without a matching close and journals killed', async () => {
|
|
const persist = new MemoryPersistAdapter()
|
|
// Pretend the process has been killed externally by the OS — kill stub is
|
|
// a noop but isPidAlive returns false because the pid is fake.
|
|
const reg = new ProcessRegistry({
|
|
persist,
|
|
kill: vi.fn(),
|
|
sleep: async () => {},
|
|
killGracePeriodMs: 0
|
|
})
|
|
// Append an orphan spawn directly (simulating a previous app instance).
|
|
await persist.appendJournal({
|
|
ts: Date.now(),
|
|
op: 'spawn',
|
|
taskId: 't1',
|
|
attemptId: 'a1',
|
|
pid: 999_999, // surely dead
|
|
pidStartedAt: 0,
|
|
exitCode: null,
|
|
signal: null
|
|
})
|
|
const reconciled = await reg.reconcile()
|
|
expect(reconciled).toHaveLength(1)
|
|
expect(reconciled[0]!.taskId).toBe('t1')
|
|
const ops = persist.journalSnapshot().map((r) => r.op)
|
|
expect(ops).toContain('killed')
|
|
})
|
|
})
|