diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index dd472df..9e06074 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -19,6 +19,8 @@ jobs: version: 0.27.23 - name: Verify package behavior run: node scripts/verify.mjs + - name: Verify process observation + run: node --test scripts/observe-process.test.mjs scripts/verify-native-web.test.mjs - name: Verify native applications if: github.event_name == 'workflow_dispatch' diff --git a/scripts/observe-process.mjs b/scripts/observe-process.mjs index 202e78d..e85f681 100644 --- a/scripts/observe-process.mjs +++ b/scripts/observe-process.mjs @@ -6,15 +6,17 @@ export function observeProcess(child, readiness, timeoutMs) { const timer = setTimeout(() => { reject(new Error(`Process startup timed out\n${diagnostics()}`)); }, timeoutMs); - child.stdout.setEncoding('utf8').on('data', chunk => { - output += chunk; - const match = output.match(readiness); - if (match) { - clearTimeout(timer); - resolve(match); - } - }); - child.stderr.setEncoding('utf8').on('data', chunk => { errors += chunk; }); + for (const [channel, stream] of [['stdout', child.stdout], ['stderr', child.stderr]]) { + stream.setEncoding('utf8').on('data', chunk => { + if (channel === 'stdout') output += chunk; + else errors += chunk; + const match = (channel === 'stdout' ? output : errors).match(readiness); + if (match) { + clearTimeout(timer); + resolve(match); + } + }); + } child.once('error', error => { clearTimeout(timer); reject(error); diff --git a/scripts/observe-process.test.mjs b/scripts/observe-process.test.mjs index c8bc8d7..8b9f012 100644 --- a/scripts/observe-process.test.mjs +++ b/scripts/observe-process.test.mjs @@ -29,6 +29,18 @@ test('recognizes fragmented readiness and retains later diagnostics', async () = assert.match(observed.diagnostics(), /after readiness/); }); +test('recognizes fragmented structured readiness on stderr', async () => { + const child = spawn(process.execPath, ['-e', + 'process.stderr.write("123 [INFO] service REA"); setTimeout(() => { process.stderr.write("DY http://127.0.0.1:1234\\n"); process.stdout.write("program output\\n"); }, 20);'], + { windowsHide: true }); + const closed = once(child, 'close'); + const observed = observeProcess(child, /READY (http:\/\/127\.0\.0\.1:\d+)\n/, 5000); + assert.equal((await observed.ready)[1], 'http://127.0.0.1:1234'); + await closed; + assert.match(observed.diagnostics(), /program output/); + assert.match(observed.diagnostics(), /123 \[INFO\] service READY/); +}); + test('timeout reports captured output and leaves process ownership with caller', async () => { const child = spawn(process.execPath, ['-e', 'console.log("booting"); setInterval(() => {}, 1000);'], { windowsHide: true });