tractor/tests/test_rpc.py

81 lines
2.1 KiB
Python

"""
RPC related
"""
import pytest
import tractor
import trio
async def sleep_back_actor(
actor_name,
func_name,
func_defined,
exposed_mods,
):
async with tractor.find_actor(actor_name) as portal:
try:
await portal.run(__name__, func_name)
except tractor.RemoteActorError as err:
if not func_defined:
expect = AttributeError
if not exposed_mods:
expect = tractor.ModuleNotExposed
assert err.type is expect
raise
async def short_sleep():
await trio.sleep(0)
@pytest.mark.parametrize(
'to_call', [
([], 'short_sleep'),
([__name__], 'short_sleep'),
([__name__], 'fake_func'),
],
ids=['no_mods', 'this_mod', 'this_mod_bad_func'],
)
def test_rpc_errors(arb_addr, to_call):
"""Test errors when making various RPC requests to an actor
that either doesn't have the requested module exposed or doesn't define
the named function.
"""
exposed_mods, funcname = to_call
func_defined = globals().get(funcname, False)
async def main():
actor = tractor.current_actor()
assert actor.is_arbiter
# spawn a subactor which calls us back
async with tractor.open_nursery() as n:
await n.run_in_actor(
'subactor',
sleep_back_actor,
actor_name=actor.name,
# function from this module the subactor will invoke
# when it RPCs back to this actor
func_name=funcname,
exposed_mods=exposed_mods,
func_defined=True if func_defined else False,
)
def run():
tractor.run(
main,
arbiter_addr=arb_addr,
rpc_module_paths=exposed_mods,
)
# handle both parameterized cases
if exposed_mods and func_defined:
run()
else:
# underlying errors are propogated upwards (yet)
with pytest.raises(tractor.RemoteActorError) as err:
run()
assert err.value.type is tractor.RemoteActorError