Bladeren bron

test(code-runtime-python): pin the stdin-close behavior with an EOF-observing case

The stdin destroy (child.stdin?.destroy() right after spawn) previously had no
in-tree coverage. A program that reads fd 0 now sees EOF immediately; without
the destroy it blocks and the run would hang to maxWallMs as a timeout —
verified fail-before by disabling the destroy (the test turns red at the wall
ceiling) and restoring it (green). The _str rebind regression was attempted but
is not viable: the success path's done-frame serialization reaches str
transitively through _encode_json_plain, which the README Known Limitations
already records as the accepted success-to-exception residual, so any rebind
test trips that documented residual before send_done's bound _str.
Chinesezjc 1 maand geleden
bovenliggende
commit
aa685028a7
1 gewijzigde bestanden met toevoegingen van 21 en 0 verwijderingen
  1. 21 0
      packages/code-runtime/code-runtime-python/tests/runtime.spec.ts

+ 21 - 0
packages/code-runtime/code-runtime-python/tests/runtime.spec.ts

@@ -725,6 +725,7 @@ describe('PythonCodeRuntime — programs and bindings', () => {
     expect(result.value).toBe('nope')
   }, 15_000)
 
+
   it('still answers the call when the rejection value cannot be converted to a string', async () => {
     // `messageOf` calls `String(error)`, which runs the value's own conversion,
     // and this call site is a DETACHED async reply callback. A rejection whose
@@ -2644,6 +2645,26 @@ describe('PythonCodeRuntime — budgets, termination, disposal', () => {
     expect(result.logs).toContain('leader-diagnostic-no-newline')
   }, 8000)
 
+  it('closes the child stdin so a program read sees EOF instead of blocking', async () => {
+    // The host closes the child's stdin write handle immediately after spawn
+    // (the program is an async body that reads nothing from fd 0; a live pipe
+    // would hold a host-side handle open past the run). A program that DOES
+    // read fd 0 therefore sees EOF at once. Fail-before: with the handle left
+    // open and no data written, `sys.stdin.read()` blocks and the run would
+    // hang to maxWallMs as a timeout.
+    const { runtime } = await setup({ maxWallMs: 8_000 })
+    const result = await runtime.run({
+      program: [
+        'import sys',
+        'data = sys.stdin.read()',
+        'return "read: " + repr(data)',
+      ].join('\n'),
+      bindings: [],
+    })
+    expect(result.error).toBeUndefined()
+    expect(result.value).toBe("read: ''")
+  }, 15_000)
+
   it('reaps a same-group child that ignores SIGTERM and releases the pipes before close', async () => {
     // The same-group counterpart to the setsid-orphan case above. A descendant
     // left in the child's OWN process group (no setsid, so `kill(-pid)` reaches