Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dec2b1f
Reapply "Port all tests to new `reg_addr` fixture name"
goodboy Mar 20, 2025
7ce4bc4
Init-support for "multi homed" transports
goodboy Sep 27, 2023
ef4c4be
Add libp2p style "multi-address" parser from `piker`
goodboy Sep 29, 2023
4db377c
Rename to `parse_maddr()` and fill out doc strings
goodboy Sep 29, 2023
7246749
Add post-mortem catch around failed transport addr binds to aid with …
goodboy Oct 3, 2023
61d82d4
Oof, default reg addrs needs to be in `list[tuple]` form..
goodboy Oct 7, 2023
2e17b08
Always set default reg addr in `find_actor()` if not defined
goodboy Oct 18, 2023
0246c82
._root: set a `_default_lo_addrs` and apply it when not provided by c…
goodboy Oct 18, 2023
94c89fd
Facepalm, `wait_for_actor()` dun take an addr `list`..
goodboy Oct 18, 2023
6d671f6
Rename fixture `arb_addr` -> `reg_addr` and set the session value glo…
goodboy Oct 18, 2023
f834b35
Ensure `registry_addrs` is always set to something
goodboy Oct 18, 2023
4868bf2
Always dynamically re-read the `._root._default_lo_addrs` value in `f…
goodboy Oct 18, 2023
51bd389
Expose per-actor registry addrs via `.reg_addrs`
goodboy Oct 19, 2023
8b0b4ab
Change remaining internals to use `Actor.reg_addrs`
goodboy Oct 19, 2023
5f0bfea
Test with `any(portals)` since `gather_contexts()` will return `list[…
goodboy Nov 6, 2023
2d541fd
Fix doc string "its" typo..
goodboy Nov 6, 2023
ebf9909
Add `open_root_actor(ensure_registry: bool)`
goodboy Nov 7, 2023
15a4a2a
`.discovery.get_arbiter()`: add warning around this now deprecated usage
goodboy Dec 12, 2023
dbd79d8
Log chan-server-startup failures via `.exception()`
goodboy Jan 2, 2024
f947bdf
Use `import <name> as <name>,` style over `__all__` in pkg mod
goodboy Jan 2, 2024
14f34c1
`_root`: drop unused `typing` import
goodboy Jan 2, 2024
9082efb
Add a `._state._runtime_vars['_registry_addrs']`
goodboy Mar 8, 2024
5ffdda7
More spaceless union type annots
goodboy Mar 11, 2024
2b12444
Unmask `pytest.ini` log-capture lines (again)
goodboy Feb 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# vim: ft=ini
# pytest.ini for tractor

[pytest]
# don't show frickin captured logs AGAIN in the report..
addopts = --show-capture='no'
log_cli = false
; minversion = 6.0
43 changes: 27 additions & 16 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,18 @@ def ci_env() -> bool:
'127.0.0.1',
random.randint(1000, 9999),
)
_arb_addr = _reg_addr


@pytest.fixture(scope='session')
def arb_addr():
return _arb_addr
def reg_addr() -> tuple[str, int]:

# globally override the runtime to the per-test-session-dynamic
# addr so that all tests never conflict with any other actor
# tree using the default.
from tractor import _root
_root._default_lo_addrs = [_reg_addr]

return _reg_addr


def pytest_generate_tests(metafunc):
Expand Down Expand Up @@ -161,30 +167,35 @@ def sig_prog(proc, sig):
def daemon(
loglevel: str,
testdir,
arb_addr: tuple[str, int],
reg_addr: tuple[str, int],
):
'''
Run a daemon actor as a "remote arbiter".
Run a daemon root actor as a separate actor-process tree and
"remote registrar" for discovery-protocol related tests.

'''
if loglevel in ('trace', 'debug'):
# too much logging will lock up the subproc (smh)
loglevel = 'info'

cmdargs = [
sys.executable, '-c',
"import tractor; tractor.run_daemon([], registry_addr={}, loglevel={})"
.format(
arb_addr,
"'{}'".format(loglevel) if loglevel else None)
# XXX: too much logging will lock up the subproc (smh)
loglevel: str = 'info'

code: str = (
"import tractor; "
"tractor.run_daemon([], registry_addrs={reg_addrs}, loglevel={ll})"
).format(
reg_addrs=str([reg_addr]),
ll="'{}'".format(loglevel) if loglevel else None,
)
cmd: list[str] = [
sys.executable,
'-c', code,
]
kwargs = dict()
kwargs = {}
if platform.system() == 'Windows':
# without this, tests hang on windows forever
kwargs['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP

proc = testdir.popen(
cmdargs,
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
**kwargs,
Expand Down
31 changes: 18 additions & 13 deletions tests/test_cancellation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from tractor._testing import (
tractor_test,
)
from .conftest import no_windows
from conftest import no_windows


def is_win():
Expand Down Expand Up @@ -45,7 +45,7 @@ async def do_nuthin():
],
ids=['no_args', 'unexpected_args'],
)
def test_remote_error(arb_addr, args_err):
def test_remote_error(reg_addr, args_err):
'''
Verify an error raised in a subactor that is propagated
to the parent nursery, contains the underlying boxed builtin
Expand All @@ -57,7 +57,7 @@ def test_remote_error(arb_addr, args_err):

async def main():
async with tractor.open_nursery(
arbiter_addr=arb_addr,
registry_addrs=[reg_addr],
) as nursery:

# on a remote type error caused by bad input args
Expand Down Expand Up @@ -99,15 +99,15 @@ async def main():
assert exc.type == errtype


def test_multierror(arb_addr):
def test_multierror(reg_addr):
'''
Verify we raise a ``BaseExceptionGroup`` out of a nursery where
more then one actor errors.

'''
async def main():
async with tractor.open_nursery(
arbiter_addr=arb_addr,
registry_addrs=[reg_addr],
) as nursery:

await nursery.run_in_actor(assert_err, name='errorer1')
Expand All @@ -132,14 +132,14 @@ async def main():
@pytest.mark.parametrize(
'num_subactors', range(25, 26),
)
def test_multierror_fast_nursery(arb_addr, start_method, num_subactors, delay):
def test_multierror_fast_nursery(reg_addr, start_method, num_subactors, delay):
"""Verify we raise a ``BaseExceptionGroup`` out of a nursery where
more then one actor errors and also with a delay before failure
to test failure during an ongoing spawning.
"""
async def main():
async with tractor.open_nursery(
arbiter_addr=arb_addr,
registry_addrs=[reg_addr],
) as nursery:

for i in range(num_subactors):
Expand Down Expand Up @@ -177,15 +177,20 @@ async def do_nothing():


@pytest.mark.parametrize('mechanism', ['nursery_cancel', KeyboardInterrupt])
def test_cancel_single_subactor(arb_addr, mechanism):
"""Ensure a ``ActorNursery.start_actor()`` spawned subactor
def test_cancel_single_subactor(reg_addr, mechanism):
'''
Ensure a ``ActorNursery.start_actor()`` spawned subactor
cancels when the nursery is cancelled.
"""

'''
async def spawn_actor():
"""Spawn an actor that blocks indefinitely.
"""
'''
Spawn an actor that blocks indefinitely then cancel via
either `ActorNursery.cancel()` or an exception raise.

'''
async with tractor.open_nursery(
arbiter_addr=arb_addr,
registry_addrs=[reg_addr],
) as nursery:

portal = await nursery.start_actor(
Expand Down
2 changes: 1 addition & 1 deletion tests/test_child_manages_service_nursery.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ async def open_actor_local_nursery(
)
def test_actor_managed_trio_nursery_task_error_cancels_aio(
asyncio_mode: bool,
arb_addr
reg_addr: tuple,
):
'''
Verify that a ``trio`` nursery created managed in a child actor
Expand Down
2 changes: 1 addition & 1 deletion tests/test_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def mk_cmd(ex_name: str) -> str:
def spawn(
start_method,
testdir,
arb_addr,
reg_addr,
) -> 'pexpect.spawn':

if start_method != 'trio':
Expand Down
76 changes: 49 additions & 27 deletions tests/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@


@tractor_test
async def test_reg_then_unreg(arb_addr):
async def test_reg_then_unreg(reg_addr):
actor = tractor.current_actor()
assert actor.is_arbiter
assert len(actor._registry) == 1 # only self is registered

async with tractor.open_nursery(
arbiter_addr=arb_addr,
registry_addrs=[reg_addr],
) as n:

portal = await n.start_actor('actor', enable_modules=[__name__])
uid = portal.channel.uid

async with tractor.get_arbiter(*arb_addr) as aportal:
async with tractor.get_arbiter(*reg_addr) as aportal:
# this local actor should be the arbiter
assert actor is aportal.actor

Expand All @@ -52,37 +52,57 @@ async def hi():
return the_line.format(tractor.current_actor().name)


async def say_hello(other_actor):
async def say_hello(
other_actor: str,
reg_addr: tuple[str, int],
):
await trio.sleep(1) # wait for other actor to spawn
async with tractor.find_actor(other_actor) as portal:
async with tractor.find_actor(
other_actor,
registry_addrs=[reg_addr],
) as portal:
assert portal is not None
return await portal.run(__name__, 'hi')


async def say_hello_use_wait(other_actor):
async with tractor.wait_for_actor(other_actor) as portal:
async def say_hello_use_wait(
other_actor: str,
reg_addr: tuple[str, int],
):
async with tractor.wait_for_actor(
other_actor,
registry_addr=reg_addr,
) as portal:
assert portal is not None
result = await portal.run(__name__, 'hi')
return result


@tractor_test
@pytest.mark.parametrize('func', [say_hello, say_hello_use_wait])
async def test_trynamic_trio(func, start_method, arb_addr):
"""Main tractor entry point, the "master" process (for now
acts as the "director").
"""
async def test_trynamic_trio(
func,
start_method,
reg_addr,
):
'''
Root actor acting as the "director" and running one-shot-task-actors
for the directed subs.

'''
async with tractor.open_nursery() as n:
print("Alright... Action!")

donny = await n.run_in_actor(
func,
other_actor='gretchen',
reg_addr=reg_addr,
name='donny',
)
gretchen = await n.run_in_actor(
func,
other_actor='donny',
reg_addr=reg_addr,
name='gretchen',
)
print(await gretchen.result())
Expand Down Expand Up @@ -130,17 +150,17 @@ async def unpack_reg(actor_or_portal):


async def spawn_and_check_registry(
arb_addr: tuple,
reg_addr: tuple,
use_signal: bool,
remote_arbiter: bool = False,
with_streaming: bool = False,

) -> None:

async with tractor.open_root_actor(
arbiter_addr=arb_addr,
registry_addrs=[reg_addr],
):
async with tractor.get_arbiter(*arb_addr) as portal:
async with tractor.get_arbiter(*reg_addr) as portal:
# runtime needs to be up to call this
actor = tractor.current_actor()

Expand Down Expand Up @@ -212,17 +232,19 @@ async def spawn_and_check_registry(
def test_subactors_unregister_on_cancel(
start_method,
use_signal,
arb_addr,
reg_addr,
with_streaming,
):
"""Verify that cancelling a nursery results in all subactors
'''
Verify that cancelling a nursery results in all subactors
deregistering themselves with the arbiter.
"""

'''
with pytest.raises(KeyboardInterrupt):
trio.run(
partial(
spawn_and_check_registry,
arb_addr,
reg_addr,
use_signal,
remote_arbiter=False,
with_streaming=with_streaming,
Expand All @@ -236,7 +258,7 @@ def test_subactors_unregister_on_cancel_remote_daemon(
daemon,
start_method,
use_signal,
arb_addr,
reg_addr,
with_streaming,
):
"""Verify that cancelling a nursery results in all subactors
Expand All @@ -247,7 +269,7 @@ def test_subactors_unregister_on_cancel_remote_daemon(
trio.run(
partial(
spawn_and_check_registry,
arb_addr,
reg_addr,
use_signal,
remote_arbiter=True,
with_streaming=with_streaming,
Expand All @@ -261,7 +283,7 @@ async def streamer(agen):


async def close_chans_before_nursery(
arb_addr: tuple,
reg_addr: tuple,
use_signal: bool,
remote_arbiter: bool = False,
) -> None:
Expand All @@ -274,9 +296,9 @@ async def close_chans_before_nursery(
entries_at_end = 1

async with tractor.open_root_actor(
arbiter_addr=arb_addr,
registry_addrs=[reg_addr],
):
async with tractor.get_arbiter(*arb_addr) as aportal:
async with tractor.get_arbiter(*reg_addr) as aportal:
try:
get_reg = partial(unpack_reg, aportal)

Expand Down Expand Up @@ -328,7 +350,7 @@ async def close_chans_before_nursery(
def test_close_channel_explicit(
start_method,
use_signal,
arb_addr,
reg_addr,
):
"""Verify that closing a stream explicitly and killing the actor's
"root nursery" **before** the containing nursery tears down also
Expand All @@ -338,7 +360,7 @@ def test_close_channel_explicit(
trio.run(
partial(
close_chans_before_nursery,
arb_addr,
reg_addr,
use_signal,
remote_arbiter=False,
),
Expand All @@ -350,7 +372,7 @@ def test_close_channel_explicit_remote_arbiter(
daemon,
start_method,
use_signal,
arb_addr,
reg_addr,
):
"""Verify that closing a stream explicitly and killing the actor's
"root nursery" **before** the containing nursery tears down also
Expand All @@ -360,7 +382,7 @@ def test_close_channel_explicit_remote_arbiter(
trio.run(
partial(
close_chans_before_nursery,
arb_addr,
reg_addr,
use_signal,
remote_arbiter=True,
),
Expand Down
Loading
Loading