// session test — the one-command flow over loopback: serveSession spawns
// mosh-server itself, connectSession requests a session and gets the key back,
// then mosh-client (driven in a PTY) runs the session through the tunnel.
import DHT from 'hyperdht'
import { spawn, execSync } from 'child_process'
import { fileURLToPath } from 'url'
import path from 'path'
import { serveSession, connectSession } from '../lib/session.mjs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
let hasMosh = true
try { execSync('command -v mosh-server && command -v mosh-client && command -v python3', { stdio: 'ignore' }) } catch { hasMosh = false }
if (!hasMosh) { console.log('session test: SKIPPED (mosh/python3 not installed)'); process.exit(0) }
console.log('[session] serveSession (spawns mosh-server) <-hyperdht-> connectSession -> mosh-client')
const keyPair = DHT.keyPair()
const s = await serveSession({ keyPair, allow: true })
let failed = false
const done = new Promise((resolve) => {
const timer = setTimeout(() => { console.log(' ❌ FAIL — no session/marker in 40s'); failed = true; resolve() }, 40000)
const session = connectSession({
remoteKey: keyPair.publicKey,
start: { term: 'xterm', cmd: ['bash', '-lc', 'echo HYPERMOSH_SESSION_OK; sleep 8'] },
onerror: (e) => { console.log(' ❌ FAIL — connect error:', e.message); failed = true; clearTimeout(timer); resolve() },
onstarted: (moshKey, localPort) => {
console.log(' session started, mosh key received; driving mosh-client on 127.0.0.1:' + localPort)
const drv = spawn('python3', [path.join(__dirname, 'pty-mosh.py'), moshKey, '127.0.0.1', String(localPort), '12'], { env: process.env })
let cap = ''
drv.stdout.on('data', (d) => { cap += d })
drv.on('exit', async () => {
const clean = cap.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, '')
if (clean.includes('HYPERMOSH_SESSION_OK')) console.log(' ✅ PASS — one-command mosh session ran end-to-end over hyperdht')
else { console.log(' ❌ FAIL — marker not seen'); failed = true }
clearTimeout(timer)
await session.close()
resolve()
})
}
})
})
await done
await s.close()
console.log(failed ? '\n❌ session test failed' : '\n✅ session test passed')
process.exit(failed ? 1 : 0)