Files
orca/config/scripts/pty-transcript-recording.test.mjs
T

183 lines
5.0 KiB
JavaScript

import { test } from 'vitest'
import assert from 'node:assert/strict'
import { PassThrough, Writable } from 'node:stream'
import { tapBunTerminalBytes } from './pty-transcript-bun-runtime.mjs'
import { recordPtyTranscript } from './pty-transcript-recording.mjs'
test('raw tap preserves invalid UTF-8, split UTF-8 and control bytes in both terminal forms', () => {
for (const inline of [true, false]) {
let options
const raw = []
const decoded = []
const runtime = {
Terminal: class {
constructor(value) {
options = value
}
},
spawn(_command, value) {
if (inline) {
options = value.terminal
}
}
}
const tapped = tapBunTerminalBytes(runtime, (bytes) => raw.push(bytes))
const terminal = { data: (_term, bytes) => decoded.push(bytes) }
tapped.spawn([], { terminal: inline ? terminal : new tapped.Terminal(terminal) })
for (const bytes of [[0xff, 0xc0], [0xe2], [0x82, 0xac, 0, 27, 13]]) {
options.data({}, Uint8Array.from(bytes))
}
assert.deepEqual(Buffer.concat(raw), Buffer.from([255, 192, 226, 130, 172, 0, 27, 13]))
assert.equal(decoded.length, 3)
}
})
function harness({ fastExit = false, stop = false } = {}) {
const stdin = new PassThrough()
const chunks = []
const sink = new Writable({
write(chunk, _encoding, done) {
chunks.push(Buffer.from(chunk))
done()
}
})
const output = []
const writes = []
let disposed = 0
return {
chunks,
writes,
get disposed() {
return disposed
},
stdin,
run: () =>
recordPtyTranscript({
sink,
stdin,
stdout: { write: (bytes) => output.push(bytes) },
options: { sends: [], duration: null },
spawn: async (data) => {
data(Buffer.from([255, 27, 13]))
let exit
const term = {
onExit(listener) {
exit = listener
if (fastExit) {
listener({ exitCode: 7 })
}
return { dispose() {} }
},
write: (bytes) => writes.push(bytes),
kill() {
data(Buffer.from('SHUTDOWN'))
exit({ exitCode: 0 })
},
destroy() {
disposed++
}
}
if (!fastExit) {
setImmediate(() => {
stdin.write(Buffer.from([0xc3, 0xa9]))
if (stop) {
stdin.write(Buffer.from([0x1d]))
} else {
data(Buffer.from([0xe2, 0x82, 0xac]))
exit({ exitCode: 3 })
}
})
}
return term
}
})
}
}
test('stop freezes transcript before killing while preserving raw input', async () => {
const fixture = harness({ stop: true })
assert.equal(await fixture.run(), 0)
assert.deepEqual(Buffer.concat(fixture.chunks), Buffer.from([255, 27, 13]))
assert.deepEqual(fixture.writes, [Buffer.from([0xc3, 0xa9])])
assert.equal(fixture.stdin.listenerCount('data'), 0)
assert.equal(fixture.disposed, 1)
})
test('natural exit retains final drained output', async () => {
const fixture = harness()
assert.equal(await fixture.run(), 3)
assert.deepEqual(Buffer.concat(fixture.chunks), Buffer.from([255, 27, 13, 226, 130, 172]))
})
test('fast exit replays completion without hanging', async () => {
const fixture = harness({ fastExit: true })
assert.equal(await fixture.run(), 7)
assert.equal(fixture.disposed, 1)
})
test('spawn receipt failure cleans input and closes output', async () => {
const stdin = new PassThrough()
const sink = new PassThrough()
let destroyed = false
await assert.rejects(
recordPtyTranscript({
stdin,
sink,
stdout: { write() {} },
options: { sends: [], duration: null },
spawn: async () => ({
onExit() {
return { dispose() {} }
},
waitForSpawn: async () => {
throw new Error('shell failed')
},
destroy() {
destroyed = true
}
})
}),
/shell failed/
)
assert.equal(destroyed, true)
assert.equal(sink.writableFinished, true)
assert.equal(stdin.listenerCount('data'), 0)
})
test('sink failure refuses success and retires terminal', async () => {
const stdin = new PassThrough()
const sink = new Writable({
write(_chunk, _encoding, done) {
done(new Error('disk full'))
}
})
let exit
let destroyed = false
await assert.rejects(
recordPtyTranscript({
stdin,
sink,
stdout: { write() {} },
options: { sends: [], duration: null },
spawn: async (data) => {
setImmediate(() => data(Buffer.from('output')))
return {
onExit(listener) {
exit = listener
return { dispose() {} }
},
kill() {
exit({ exitCode: 1 })
},
destroy() {
destroyed = true
}
}
}
}),
/disk full/
)
assert.equal(destroyed, true)
assert.equal(stdin.listenerCount('data'), 0)
})