Wire `reg_addr` through infected-asyncio tests

Continues the hygiene pattern from de601676 (cancel tests) into
`tests/test_infected_asyncio.py`: many tests here were calling
`tractor.open_nursery()` w/o `registry_addrs=[reg_addr]` and thus racing
on the default `:1616` registry across sessions. Thread the
session-unique `reg_addr` through so leaked or slow-to-teardown
subactors from a prior test can't cross-pollute.

Deats,
- add `registry_addrs=[reg_addr]` to `open_nursery()`
  calls in suite where missing.
- `test_sigint_closes_lifetime_stack`:
  - add `reg_addr`, `debug_mode`, `start_method`
    fixture params
  - `delay` now reads the `debug_mode` param directly
    instead of calling `tractor.debug_mode()` (fires
    slightly earlier in the test lifecycle)
  - sanity assert `if debug_mode: assert
    tractor.debug_mode()` after nursery open
  - new print showing SIGINT target
    (`send_sigint_to` + resolved pid)
  - catch `trio.TooSlowError` around
    `ctx.wait_for_result()` and conditionally
    `pytest.xfail` when `send_sigint_to == 'child'
    and start_method == 'subint_forkserver'` — the
    known orphan-SIGINT limitation tracked in
    `ai/conc-anal/subint_forkserver_orphan_sigint_hang_issue.md`
- parametrize id typo fix: `'just_trio_slee'` → `'just_trio_sleep'`

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
subint_forkserver_backend
Gud Boi 2026-04-24 20:26:25 -04:00
parent d6e70e9de4
commit b350aa09ee
1 changed files with 70 additions and 13 deletions

View File

@ -183,6 +183,7 @@ def test_tractor_cancels_aio(
async def main(): async def main():
async with tractor.open_nursery( async with tractor.open_nursery(
debug_mode=debug_mode, debug_mode=debug_mode,
registry_addrs=[reg_addr],
) as an: ) as an:
portal = await an.run_in_actor( portal = await an.run_in_actor(
asyncio_actor, asyncio_actor,
@ -205,11 +206,11 @@ def test_trio_cancels_aio(
''' '''
async def main(): async def main():
# cancel the nursery shortly after boot
with trio.move_on_after(1): with trio.move_on_after(1):
# cancel the nursery shortly after boot async with tractor.open_nursery(
registry_addrs=[reg_addr],
async with tractor.open_nursery() as tn: ) as tn:
await tn.run_in_actor( await tn.run_in_actor(
asyncio_actor, asyncio_actor,
target='aio_sleep_forever', target='aio_sleep_forever',
@ -277,7 +278,9 @@ def test_context_spawns_aio_task_that_errors(
''' '''
async def main(): async def main():
with trio.fail_after(1 + delay): with trio.fail_after(1 + delay):
async with tractor.open_nursery() as an: async with tractor.open_nursery(
registry_addrs=[reg_addr],
) as an:
p = await an.start_actor( p = await an.start_actor(
'aio_daemon', 'aio_daemon',
enable_modules=[__name__], enable_modules=[__name__],
@ -360,7 +363,9 @@ def test_aio_cancelled_from_aio_causes_trio_cancelled(
async def main(): async def main():
an: tractor.ActorNursery an: tractor.ActorNursery
async with tractor.open_nursery() as an: async with tractor.open_nursery(
registry_addrs=[reg_addr],
) as an:
p: tractor.Portal = await an.run_in_actor( p: tractor.Portal = await an.run_in_actor(
asyncio_actor, asyncio_actor,
target='aio_cancel', target='aio_cancel',
@ -569,7 +574,9 @@ def test_basic_interloop_channel_stream(
async def main(): async def main():
# TODO, figure out min timeout here! # TODO, figure out min timeout here!
with trio.fail_after(6): with trio.fail_after(6):
async with tractor.open_nursery() as an: async with tractor.open_nursery(
registry_addrs=[reg_addr],
) as an:
portal = await an.run_in_actor( portal = await an.run_in_actor(
stream_from_aio, stream_from_aio,
infect_asyncio=True, infect_asyncio=True,
@ -582,9 +589,13 @@ def test_basic_interloop_channel_stream(
# TODO: parametrize the above test and avoid the duplication here? # TODO: parametrize the above test and avoid the duplication here?
def test_trio_error_cancels_intertask_chan(reg_addr): def test_trio_error_cancels_intertask_chan(
reg_addr: tuple[str, int],
):
async def main(): async def main():
async with tractor.open_nursery() as an: async with tractor.open_nursery(
registry_addrs=[reg_addr],
) as an:
portal = await an.run_in_actor( portal = await an.run_in_actor(
stream_from_aio, stream_from_aio,
trio_raise_err=True, trio_raise_err=True,
@ -619,6 +630,7 @@ def test_trio_closes_early_causes_aio_checkpoint_raise(
async with tractor.open_nursery( async with tractor.open_nursery(
debug_mode=debug_mode, debug_mode=debug_mode,
# enable_stack_on_sig=True, # enable_stack_on_sig=True,
registry_addrs=[reg_addr],
) as an: ) as an:
portal = await an.run_in_actor( portal = await an.run_in_actor(
stream_from_aio, stream_from_aio,
@ -667,6 +679,7 @@ def test_aio_exits_early_relays_AsyncioTaskExited(
async def main(): async def main():
with trio.fail_after(1 + delay): with trio.fail_after(1 + delay):
async with tractor.open_nursery( async with tractor.open_nursery(
registry_addrs=[reg_addr],
debug_mode=debug_mode, debug_mode=debug_mode,
# enable_stack_on_sig=True, # enable_stack_on_sig=True,
) as an: ) as an:
@ -707,6 +720,7 @@ def test_aio_errors_and_channel_propagates_and_closes(
): ):
async def main(): async def main():
async with tractor.open_nursery( async with tractor.open_nursery(
registry_addrs=[reg_addr],
debug_mode=debug_mode, debug_mode=debug_mode,
) as an: ) as an:
portal = await an.run_in_actor( portal = await an.run_in_actor(
@ -806,6 +820,7 @@ def test_echoserver_detailed_mechanics(
): ):
async def main(): async def main():
async with tractor.open_nursery( async with tractor.open_nursery(
registry_addrs=[reg_addr],
debug_mode=debug_mode, debug_mode=debug_mode,
) as an: ) as an:
p = await an.start_actor( p = await an.start_actor(
@ -984,7 +999,7 @@ async def manage_file(
], ],
ids=[ ids=[
'bg_aio_task', 'bg_aio_task',
'just_trio_slee', 'just_trio_sleep',
], ],
) )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -1000,11 +1015,14 @@ async def manage_file(
) )
def test_sigint_closes_lifetime_stack( def test_sigint_closes_lifetime_stack(
tmp_path: Path, tmp_path: Path,
reg_addr: tuple,
debug_mode: bool,
wait_for_ctx: bool, wait_for_ctx: bool,
bg_aio_task: bool, bg_aio_task: bool,
trio_side_is_shielded: bool, trio_side_is_shielded: bool,
debug_mode: bool,
send_sigint_to: str, send_sigint_to: str,
start_method: str,
): ):
''' '''
Ensure that an infected child can use the `Actor.lifetime_stack` Ensure that an infected child can use the `Actor.lifetime_stack`
@ -1014,12 +1032,22 @@ def test_sigint_closes_lifetime_stack(
''' '''
async def main(): async def main():
delay = 999 if tractor.debug_mode() else 1 delay: float = (
999
if debug_mode
else 1
)
try: try:
an: tractor.ActorNursery an: tractor.ActorNursery
async with tractor.open_nursery( async with tractor.open_nursery(
registry_addrs=[reg_addr],
debug_mode=debug_mode, debug_mode=debug_mode,
) as an: ) as an:
# sanity
if debug_mode:
assert tractor.debug_mode()
p: tractor.Portal = await an.start_actor( p: tractor.Portal = await an.start_actor(
'file_mngr', 'file_mngr',
enable_modules=[__name__], enable_modules=[__name__],
@ -1054,6 +1082,10 @@ def test_sigint_closes_lifetime_stack(
cpid if send_sigint_to == 'child' cpid if send_sigint_to == 'child'
else os.getpid() else os.getpid()
) )
print(
f'Sending SIGINT to {send_sigint_to!r}\n'
f'pid: {pid!r}\n'
)
os.kill( os.kill(
pid, pid,
signal.SIGINT, signal.SIGINT,
@ -1064,13 +1096,37 @@ def test_sigint_closes_lifetime_stack(
# timeout should trigger! # timeout should trigger!
if wait_for_ctx: if wait_for_ctx:
print('waiting for ctx outcome in parent..') print('waiting for ctx outcome in parent..')
if debug_mode:
assert delay == 999
try: try:
with trio.fail_after(1 + delay): with trio.fail_after(
1 + delay
):
await ctx.wait_for_result() await ctx.wait_for_result()
except tractor.ContextCancelled as ctxc: except tractor.ContextCancelled as ctxc:
assert ctxc.canceller == ctx.chan.uid assert ctxc.canceller == ctx.chan.uid
raise raise
except trio.TooSlowError:
if (
send_sigint_to == 'child'
and
start_method == 'subint_forkserver'
):
pytest.xfail(
reason=(
'SIGINT delivery to fork-child subactor is known '
'to NOT SUCCEED, precisely bc we have not wired up a'
'"trio SIGINT mode" in the child pre-fork.\n'
'Also see `test_orphaned_subactor_sigint_cleanup_DRAFT` for'
'a dedicated suite demonstrating this expected limitation as '
'well as the detailed doc:\n'
'`ai/conc-anal/subint_forkserver_orphan_sigint_hang_issue.md`.\n'
),
)
# XXX CASE 2: this seems to be the source of the # XXX CASE 2: this seems to be the source of the
# original issue which exhibited BEFORE we put # original issue which exhibited BEFORE we put
# a `Actor.cancel_soon()` inside # a `Actor.cancel_soon()` inside
@ -1170,6 +1226,7 @@ def test_aio_side_raises_before_started(
with trio.fail_after(3): with trio.fail_after(3):
an: tractor.ActorNursery an: tractor.ActorNursery
async with tractor.open_nursery( async with tractor.open_nursery(
registry_addrs=[reg_addr],
debug_mode=debug_mode, debug_mode=debug_mode,
loglevel=loglevel, loglevel=loglevel,
) as an: ) as an: