forked from goodboy/tractor
Add a multi-subactor test with nesting
parent
a2151cdd4d
commit
e387e8b322
|
@ -1,39 +0,0 @@
|
|||
import tractor
|
||||
import trio
|
||||
|
||||
|
||||
async def bubble():
|
||||
print('IN BUBBLE')
|
||||
while True:
|
||||
await trio.sleep(.1)
|
||||
await tractor.breakpoint()
|
||||
|
||||
|
||||
async def name_error():
|
||||
getattr(doggy)
|
||||
|
||||
|
||||
async def main():
|
||||
"""The main ``tractor`` routine.
|
||||
"""
|
||||
async with tractor.open_nursery() as n:
|
||||
|
||||
portal1 = await n.run_in_actor('bubble', bubble)
|
||||
portal = await n.run_in_actor('name_error', name_error)
|
||||
await portal1.result()
|
||||
await portal.result()
|
||||
|
||||
# The ``async with`` will unblock here since the 'some_linguist'
|
||||
# actor has completed its main task ``cellar_door``.
|
||||
|
||||
|
||||
# TODO:
|
||||
# - recurrent entry from single actor
|
||||
# - recurrent entry to breakpoint() from single actor *after* and an
|
||||
# error
|
||||
# - root error alongside child errors
|
||||
# - recurrent root errors
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
tractor.run(main, loglevel='info', debug_mode=True)
|
|
@ -0,0 +1,51 @@
|
|||
import tractor
|
||||
import trio
|
||||
|
||||
|
||||
async def breakpoint_forever():
|
||||
"Indefinitely re-enter debugger in child actor."
|
||||
while True:
|
||||
await trio.sleep(0.1)
|
||||
await tractor.breakpoint()
|
||||
|
||||
|
||||
async def name_error():
|
||||
"Raise a ``NameError``"
|
||||
getattr(doggypants)
|
||||
|
||||
|
||||
async def spawn_error():
|
||||
""""A nested nursery that triggers another ``NameError``.
|
||||
"""
|
||||
async with tractor.open_nursery() as n:
|
||||
portal = await n.run_in_actor('name_error_1', name_error)
|
||||
return await portal.result()
|
||||
|
||||
|
||||
async def main():
|
||||
"""The main ``tractor`` routine.
|
||||
|
||||
The process tree should look as approximately as follows:
|
||||
|
||||
-python examples/debugging/multi_subactors.py
|
||||
|-python -m tractor._child --uid ('name_error', 'a7caf490 ...)
|
||||
|-python -m tractor._child --uid ('bp_forever', '1f787a7e ...)
|
||||
`-python -m tractor._child --uid ('spawn_error', '52ee14a5 ...)
|
||||
`-python -m tractor._child --uid ('name_error', '3391222c ...)
|
||||
"""
|
||||
async with tractor.open_nursery() as n:
|
||||
|
||||
# spawn both actors
|
||||
portal1 = await n.run_in_actor('bp_forever', breakpoint_forever)
|
||||
portal = await n.run_in_actor('name_error', name_error)
|
||||
portal2 = await n.run_in_actor('spawn_error', spawn_error)
|
||||
|
||||
# attempt to collect results (which raises error in parent)
|
||||
# still has some issues where the parent seems to get stuck
|
||||
# await portal.result()
|
||||
# await portal1.result()
|
||||
# await portal2.result()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
tractor.run(main, debug_mode=True)
|
|
@ -9,6 +9,17 @@ import pexpect
|
|||
from .test_docs_examples import repodir
|
||||
|
||||
|
||||
# TODO:
|
||||
# - recurrent entry from single actor
|
||||
# - recurrent entry to breakpoint() from single actor *after* and an
|
||||
# error
|
||||
# - root error before child errors
|
||||
# - root error after child errors
|
||||
# - root error before child breakpoint
|
||||
# - root error after child breakpoint
|
||||
# - recurrent root errors
|
||||
|
||||
|
||||
def examples_dir():
|
||||
"""Return the abspath to the examples directory.
|
||||
"""
|
||||
|
@ -45,7 +56,7 @@ def spawn(
|
|||
('c', 'AssertionError'),
|
||||
('q', 'AssertionError'),
|
||||
],
|
||||
ids=lambda item: item[1],
|
||||
ids=lambda item: f'{item[0]} -> {item[1]}',
|
||||
)
|
||||
def test_root_actor_error(spawn, user_in_out):
|
||||
"""Demonstrate crash handler entering pdbpp from basic error in root actor.
|
||||
|
@ -55,7 +66,7 @@ def test_root_actor_error(spawn, user_in_out):
|
|||
child = spawn('root_actor_error')
|
||||
|
||||
# scan for the pdbpp prompt
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
# make sure expected logging and error arrives
|
||||
assert 'TTY lock acquired' in str(child.before)
|
||||
|
@ -86,7 +97,7 @@ def test_root_actor_bp(spawn, user_in_out):
|
|||
child = spawn('root_actor_breakpoint')
|
||||
|
||||
# scan for the pdbpp prompt
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
assert 'Error' not in str(child.before)
|
||||
|
||||
|
@ -104,10 +115,12 @@ def test_root_actor_bp(spawn, user_in_out):
|
|||
|
||||
|
||||
def test_subactor_error(spawn):
|
||||
"Single subactor raising an error"
|
||||
|
||||
child = spawn('subactor_error')
|
||||
|
||||
# scan for the pdbpp prompt
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
before = str(child.before.decode())
|
||||
assert "Attaching to pdb in crashed actor: ('name_error'" in before
|
||||
|
@ -120,7 +133,7 @@ def test_subactor_error(spawn):
|
|||
# the debugger should enter a second time in the nursery
|
||||
# creating actor
|
||||
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
before = str(child.before.decode())
|
||||
|
||||
|
@ -138,10 +151,12 @@ def test_subactor_error(spawn):
|
|||
|
||||
|
||||
def test_subactor_breakpoint(spawn):
|
||||
"Single subactor with an infinite breakpoint loop"
|
||||
|
||||
child = spawn('subactor_breakpoint')
|
||||
|
||||
# scan for the pdbpp prompt
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
before = str(child.before.decode())
|
||||
assert "Attaching pdb to actor: ('breakpoint_forever'" in before
|
||||
|
@ -150,12 +165,12 @@ def test_subactor_breakpoint(spawn):
|
|||
# entries
|
||||
for _ in range(10):
|
||||
child.sendline('next')
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
# now run some "continues" to show re-entries
|
||||
for _ in range(5):
|
||||
child.sendline('continue')
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
before = str(child.before.decode())
|
||||
assert "Attaching pdb to actor: ('breakpoint_forever'" in before
|
||||
|
||||
|
@ -163,7 +178,7 @@ def test_subactor_breakpoint(spawn):
|
|||
child.sendline('q')
|
||||
|
||||
# child process should exit but parent will capture pdb.BdbQuit
|
||||
child.expect("\(Pdb\+\+\)")
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
before = str(child.before.decode())
|
||||
assert "RemoteActorError: ('breakpoint_forever'" in before
|
||||
|
@ -178,3 +193,65 @@ def test_subactor_breakpoint(spawn):
|
|||
before = str(child.before.decode())
|
||||
assert "RemoteActorError: ('breakpoint_forever'" in before
|
||||
assert 'bdb.BdbQuit' in before
|
||||
|
||||
|
||||
def test_multi_subactors(spawn):
|
||||
"""Multiple subactors, both erroring and breakpointing as well as
|
||||
a nested subactor erroring.
|
||||
"""
|
||||
child = spawn(r'multi_subactors')
|
||||
|
||||
# scan for the pdbpp prompt
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
before = str(child.before.decode())
|
||||
assert "Attaching pdb to actor: ('bp_forever'" in before
|
||||
|
||||
# do some "next" commands to demonstrate recurrent breakpoint
|
||||
# entries
|
||||
for _ in range(10):
|
||||
child.sendline('next')
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
# continue to next error
|
||||
child.sendline('c')
|
||||
|
||||
# first name_error failure
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
before = str(child.before.decode())
|
||||
assert "NameError" in before
|
||||
|
||||
# continue again
|
||||
child.sendline('c')
|
||||
|
||||
# 2nd name_error failure
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
before = str(child.before.decode())
|
||||
assert "NameError" in before
|
||||
|
||||
# breakpoint loop should re-engage
|
||||
child.sendline('c')
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
before = str(child.before.decode())
|
||||
assert "Attaching pdb to actor: ('bp_forever'" in before
|
||||
|
||||
# now run some "continues" to show re-entries
|
||||
for _ in range(5):
|
||||
child.sendline('c')
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
# quit the loop and expect parent to attach
|
||||
child.sendline('q')
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
before = str(child.before.decode())
|
||||
assert "Attaching to pdb in crashed actor: ('arbiter'" in before
|
||||
assert "RemoteActorError: ('bp_forever'" in before
|
||||
assert 'bdb.BdbQuit' in before
|
||||
|
||||
# process should exit
|
||||
child.sendline('c')
|
||||
child.expect(pexpect.EOF)
|
||||
|
||||
before = str(child.before.decode())
|
||||
assert "RemoteActorError: ('bp_forever'" in before
|
||||
assert 'bdb.BdbQuit' in before
|
||||
|
|
Loading…
Reference in New Issue