tractor/tests
Gud Boi 253e7cbd1c Add DRAFT `subint_forkserver` orphan-SIGINT test
Tier-4 test `test_orphaned_subactor_sigint_cleanup_DRAFT`
documents an empirical SIGINT-delivery gap in the
`subint_forkserver` backend: when the parent dies via
`SIGKILL` (no IPC `Portal.cancel_actor()` possible) and
`SIGINT` is sent to the orphan child, the child DOES NOT
unwind — CPython's default `KeyboardInterrupt` is delivered
to `threading.main_thread()`, whose tstate is dead in the
post-fork child bc fork inherited the worker thread, not
main. Trio running on the fork-inherited worker thread
therefore never observes the signal. Marked
`xfail(strict=True)` so the mark flips to XPASS→fail once
the backend grows explicit SIGINT plumbing.

Deats,
- harness runs the failure-mode sequence out-of-process:
  1. harness subprocess runs a fresh Python script
     that calls `try_set_start_method('subint_forkserver')`
     then opens a root actor + one `sleep_forever` subactor
  2. parse `PARENT_READY=<pid>` + `CHILD_PID=<pid>` markers
     off harness `stdout` to confirm IPC handshake
     completed
  3. `SIGKILL` the parent, `proc.wait()` to reap the
     zombie (otherwise `os.kill(pid, 0)` keeps reporting
     it alive)
  4. assert the child survived the parent-reap (i.e. was
     actually orphaned, not reaped too) before moving on
  5. `SIGINT` the orphan child, poll `os.kill(child_pid, 0)`
     every 100ms for up to 10s
- supporting helpers: `_read_marker()` with per-proc
  bytes-buffer to carry partial lines across calls,
  `_process_alive()` liveness probe via `kill(pid, 0)`
- Linux-only via `platform.system() != 'Linux'` skip —
  orphan-reparenting semantics don't generalize to
  other platforms
- port offset (`reg_addr[1] + 17`) so the harness listener
  doesn't race concurrently-running backend tests
- best-effort `finally:` cleanup: `SIGKILL` any still-alive
  pids + `proc.kill()` + bounded `proc.wait()` to avoid
  leaking orphans across the session

Also, tier-4 header comment documents the cross-backend
generalization path: applicable to any multi-process
backend (`trio`, `mp_spawn`, `mp_forkserver`,
`subint_forkserver`), NOT to plain `subint` (in-process
subints have no orphan OS-child). Move path: lift
harness into `tests/_orphan_harness.py`, parametrize on
session `_spawn_method`, add
`skipif _spawn_method == 'subint'`.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-04-22 19:39:41 -04:00
..
devx Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
discovery Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
ipc Update tests+examples imports for new subpkgs 2026-04-02 17:59:13 -04:00
msg Update tests+examples imports for new subpkgs 2026-04-02 17:59:13 -04:00
spawn Add DRAFT `subint_forkserver` orphan-SIGINT test 2026-04-22 19:39:41 -04:00
__init__.py Add `tests/__init__.py` for `.conftest` imports 2025-03-20 20:53:54 -04:00
conftest.py Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
test_2way.py Tidy a typing-typo, add explicit `ids=` for paramed suites 2026-03-09 19:35:47 -04:00
test_advanced_faults.py Revert advanced-fault UDS edge case handling 2026-03-13 21:10:52 -04:00
test_advanced_streaming.py Remove lingering seg=False-flags from tests 2025-08-18 12:03:32 -04:00
test_cancellation.py Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
test_child_manages_service_nursery.py Swap `open_channel_from()` to yield `(chan, first)` 2026-03-13 19:28:57 -04:00
test_clustering.py Skip `test_empty_mngrs_input_raises` on UDS tpt 2026-04-02 17:59:13 -04:00
test_context_stream_semantics.py Update tests+examples imports for new subpkgs 2026-04-02 17:59:13 -04:00
test_docs_examples.py Move `get_cpu_state()` to `conftest` as shared latency headroom 2026-04-02 17:59:13 -04:00
test_infected_asyncio.py Update tests+examples imports for new subpkgs 2026-04-02 17:59:13 -04:00
test_inter_peer_cancellation.py Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
test_legacy_one_way_streaming.py Move `get_cpu_state()` to `conftest` as shared latency headroom 2026-04-02 17:59:13 -04:00
test_local.py Rename `Arbiter` -> `Registrar`, mv to `discovery._registry` 2026-04-02 17:59:13 -04:00
test_log_sys.py Mk `test_implicit_mod_name_applied_for_child()` check init-mods 2026-02-11 21:43:37 -05:00
test_multi_program.py Rename `discovery._discovery` to `._api` 2026-04-14 19:54:14 -04:00
test_oob_cancellation.py Woops, fix missing `assert` thanks to copilot 2025-09-11 13:13:18 -04:00
test_pubsub.py Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
test_reg_err_types.py Drop stale `.cancel()`, fix docstring typo in tests 2026-04-02 18:21:19 -04:00
test_remote_exc_relay.py Adjust ep-masking-suite for the real-use-case 2025-07-15 07:23:21 -04:00
test_resource_cache.py Scale `test_open_local_sub_to_stream` timeout by CPU factor 2026-04-16 20:03:32 -04:00
test_ringbuf.py Avoid skip `.ipc._ringbuf` import when no `cffi` 2026-04-20 16:39:32 -04:00
test_root_infect_asyncio.py Swap `open_channel_from()` to yield `(chan, first)` 2026-03-13 19:28:57 -04:00
test_root_runtime.py Update tests+examples imports for new subpkgs 2026-04-02 17:59:13 -04:00
test_rpc.py Rename `Arbiter` -> `Registrar`, mv to `discovery._registry` 2026-04-02 17:59:13 -04:00
test_runtime.py Repair lifetime-stack suite's flakiness 2026-03-13 21:10:52 -04:00
test_shm.py Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
test_spawning.py Tweak timeouts and rm `arbiter_addr` in tests 2026-04-14 19:54:14 -04:00
test_subint_cancellation.py Mark `subint`-hanging tests with `skipon_spawn_backend` 2026-04-21 21:33:15 -04:00
test_task_broadcasting.py Tweak timeouts and rm `arbiter_addr` in tests 2026-04-14 19:54:14 -04:00
test_trioisms.py Tweaks from copilot, type fix, typos, language. 2025-09-11 10:01:25 -04:00