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
parent
d6e70e9de4
commit
b350aa09ee
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue