mirror of
https://github.com/stablyai/orca.git
synced 2026-09-24 08:02:33 +00:00
149 lines
4.3 KiB
JavaScript
149 lines
4.3 KiB
JavaScript
const assert = require('node:assert/strict')
|
|
const { EventEmitter2 } = require('node-pty/lib/eventEmitter2')
|
|
|
|
function nativePort() {
|
|
const data = new EventEmitter2()
|
|
const exit = new EventEmitter2()
|
|
const calls = { writes: 0, resizes: 0, pauses: 0, resumes: 0, kills: 0, destroys: 0 }
|
|
return {
|
|
process: {
|
|
pid: 0,
|
|
process: 'audit-shell',
|
|
onData: data.event,
|
|
onExit: exit.event,
|
|
write() {
|
|
calls.writes++
|
|
},
|
|
resize() {
|
|
calls.resizes++
|
|
},
|
|
pause() {
|
|
calls.pauses++
|
|
},
|
|
resume() {
|
|
calls.resumes++
|
|
},
|
|
clear() {},
|
|
kill() {
|
|
calls.kills++
|
|
},
|
|
destroy() {
|
|
calls.destroys++
|
|
}
|
|
},
|
|
emitData: (value) => data.fire(value),
|
|
emitExit: (value) => exit.fire(value),
|
|
calls
|
|
}
|
|
}
|
|
|
|
function start(create, reportsChildExitStatus) {
|
|
const native = nativePort()
|
|
const env = { PATH: '/synthetic/audit/bin', RETENTION_FIXTURE: 'small ordinary field' }
|
|
const args = {
|
|
process: native.process,
|
|
shellPath: '/synthetic/audit-shell',
|
|
spawnCwd: '/synthetic',
|
|
requestedCwd: '/synthetic',
|
|
sessionId: 'native-env-audit',
|
|
startupAgentRecognition: null,
|
|
env,
|
|
startupCommandDeliveredInShellArgs: true,
|
|
reportsChildExitStatus
|
|
}
|
|
return {
|
|
handle: create(args),
|
|
native,
|
|
refs: { args: new WeakRef(args), env: new WeakRef(env) }
|
|
}
|
|
}
|
|
|
|
async function collect() {
|
|
for (let round = 0; round < 6; round++) {
|
|
await new Promise(setImmediate)
|
|
global.gc()
|
|
}
|
|
}
|
|
function counts(refs) {
|
|
return Object.fromEntries(
|
|
['args', 'env'].map((key) => [key, refs.filter((ref) => ref[key].deref()).length])
|
|
)
|
|
}
|
|
|
|
async function run(create, fixed) {
|
|
const originalKill = process.kill
|
|
const nativeSignals = []
|
|
process.kill = (...args) => {
|
|
nativeSignals.push(args)
|
|
throw new Error('No OS signal permitted in proof')
|
|
}
|
|
try {
|
|
let owner = start(create, true)
|
|
const refs = [owner.refs]
|
|
await collect()
|
|
const whileLive = counts(refs)
|
|
assert.deepEqual(whileLive, { args: fixed ? 0 : 1, env: fixed ? 0 : 1 })
|
|
assert.equal(owner.handle.shellPathEnv, '/synthetic/audit/bin')
|
|
assert.equal(owner.handle.startupCommandDeliveredInShellArgs, true)
|
|
assert.equal(owner.handle.getForegroundProcess({ rawFallback: true }), 'audit-shell')
|
|
const output = []
|
|
const exits = []
|
|
owner.native.emitData('early-output')
|
|
owner.handle.onData((data) => output.push(data))
|
|
owner.handle.onExit((code, cause) => exits.push({ code, cause }))
|
|
owner.handle.write('a')
|
|
owner.handle.resize(80, 24)
|
|
owner.handle.pause()
|
|
owner.handle.resume()
|
|
owner.native.emitExit({ exitCode: 7, signal: 0 })
|
|
assert.deepEqual(exits, [{ code: 7, cause: { kind: 'exited', exitCode: 7 } }])
|
|
assert.deepEqual(output, ['early-output'])
|
|
owner.handle.write('after-exit')
|
|
owner.handle.kill()
|
|
owner.handle.forceKill()
|
|
owner.handle.signal('SIGKILL')
|
|
assert.equal(owner.native.calls.writes, 1)
|
|
assert.equal(owner.native.calls.kills, 0)
|
|
owner.handle.dispose()
|
|
owner.handle.dispose()
|
|
assert.equal(owner.native.calls.destroys, 1)
|
|
owner = null
|
|
await collect()
|
|
const afterOwnerDrop = counts(refs)
|
|
assert.deepEqual(afterOwnerDrop, { args: 0, env: 0 })
|
|
|
|
const unavailable = start(create, false)
|
|
const unavailableExits = []
|
|
unavailable.native.emitExit({ exitCode: 0, signal: 9 })
|
|
unavailable.handle.onExit((code, cause) => unavailableExits.push({ code, cause }))
|
|
assert.deepEqual(unavailableExits, [
|
|
{ code: 0, cause: { kind: 'unknown', reason: 'host_status_unavailable' } }
|
|
])
|
|
unavailable.handle.dispose()
|
|
const signaled = start(create, true)
|
|
const signaledExits = []
|
|
signaled.handle.onExit((code, cause) => signaledExits.push({ code, cause }))
|
|
signaled.native.emitExit({ exitCode: 0, signal: 9 })
|
|
assert.deepEqual(signaledExits, [{ code: 0, cause: { kind: 'signaled', signal: 9 } }])
|
|
signaled.handle.dispose()
|
|
assert.deepEqual(nativeSignals, [])
|
|
return {
|
|
whileLive,
|
|
afterOwnerDrop,
|
|
controls: [
|
|
'PATH retained',
|
|
'raw foreground receiver',
|
|
'pre-listener data/exit',
|
|
'status unavailable',
|
|
'signal cause',
|
|
'dead signal guard',
|
|
'idempotent dispose'
|
|
]
|
|
}
|
|
} finally {
|
|
process.kill = originalKill
|
|
}
|
|
}
|
|
|
|
module.exports = run
|