Add tests for import-time failures

contexts
Tyler Goodlet 2019-01-12 17:56:39 -05:00
parent 06c908f285
commit d2f0537850
1 changed files with 59 additions and 22 deletions

View File

@ -1,6 +1,8 @@
""" """
RPC related RPC related
""" """
import itertools
import pytest import pytest
import tractor import tractor
import trio import trio
@ -12,17 +14,20 @@ async def sleep_back_actor(
func_defined, func_defined,
exposed_mods, exposed_mods,
): ):
async with tractor.find_actor(actor_name) as portal: if actor_name:
try: async with tractor.find_actor(actor_name) as portal:
await portal.run(__name__, func_name) try:
except tractor.RemoteActorError as err: await portal.run(__name__, func_name)
if not func_defined: except tractor.RemoteActorError as err:
expect = AttributeError if not func_defined:
if not exposed_mods: expect = AttributeError
expect = tractor.ModuleNotExposed if not exposed_mods:
expect = tractor.ModuleNotExposed
assert err.type is expect assert err.type is expect
raise raise
else:
await trio.sleep(float('inf'))
async def short_sleep(): async def short_sleep():
@ -31,19 +36,40 @@ async def short_sleep():
@pytest.mark.parametrize( @pytest.mark.parametrize(
'to_call', [ 'to_call', [
([], 'short_sleep'), ([], 'short_sleep', tractor.RemoteActorError),
([__name__], 'short_sleep'), ([__name__], 'short_sleep', tractor.RemoteActorError),
([__name__], 'fake_func'), ([__name__], 'fake_func', tractor.RemoteActorError),
(['tmp_mod'], 'import doggy', ModuleNotFoundError),
(['tmp_mod'], '4doggy', SyntaxError),
], ],
ids=['no_mods', 'this_mod', 'this_mod_bad_func'], ids=['no_mods', 'this_mod', 'this_mod_bad_func', 'fail_to_import',
'fail_on_syntax'],
) )
def test_rpc_errors(arb_addr, to_call): def test_rpc_errors(arb_addr, to_call, testdir):
"""Test errors when making various RPC requests to an actor """Test errors when making various RPC requests to an actor
that either doesn't have the requested module exposed or doesn't define that either doesn't have the requested module exposed or doesn't define
the named function. the named function.
""" """
exposed_mods, funcname = to_call exposed_mods, funcname, inside_err = to_call
subactor_exposed_mods = []
func_defined = globals().get(funcname, False) func_defined = globals().get(funcname, False)
subactor_requests_to = 'arbiter'
remote_err = tractor.RemoteActorError
# remote module that fails at import time
if exposed_mods == ['tmp_mod']:
# create an importable module with a bad import
testdir.syspathinsert()
# module should cause raise a ModuleNotFoundError at import
testdir.makefile('.py', tmp_mod=funcname)
# no need to exposed module to the subactor
subactor_exposed_mods = exposed_mods
exposed_mods = []
func_defined = False
# subactor should not try to invoke anything
subactor_requests_to = None
remote_err = trio.MultiError
async def main(): async def main():
actor = tractor.current_actor() actor = tractor.current_actor()
@ -54,12 +80,13 @@ def test_rpc_errors(arb_addr, to_call):
await n.run_in_actor( await n.run_in_actor(
'subactor', 'subactor',
sleep_back_actor, sleep_back_actor,
actor_name=actor.name, actor_name=subactor_requests_to,
# function from this module the subactor will invoke # function from the local exposed module space
# when it RPCs back to this actor # the subactor will invoke when it RPCs back to this actor
func_name=funcname, func_name=funcname,
exposed_mods=exposed_mods, exposed_mods=exposed_mods,
func_defined=True if func_defined else False, func_defined=True if func_defined else False,
rpc_module_paths=subactor_exposed_mods,
) )
def run(): def run():
@ -73,8 +100,18 @@ def test_rpc_errors(arb_addr, to_call):
if exposed_mods and func_defined: if exposed_mods and func_defined:
run() run()
else: else:
# underlying errors are propogated upwards (yet) # underlying errors are propagated upwards (yet)
with pytest.raises(tractor.RemoteActorError) as err: with pytest.raises(remote_err) as err:
run() run()
assert err.value.type is tractor.RemoteActorError # get raw instance from pytest wrapper
value = err.value
# might get multiple `trio.Cancelled`s as well inside an inception
if isinstance(value, trio.MultiError):
value = next(itertools.dropwhile(
lambda exc: not isinstance(exc, tractor.RemoteActorError),
value.exceptions
))
assert value.type is inside_err