Fix multi-daemon debug test `break` signal..

It was expecting `AssertionError` as a proceed-in-test signal (by
breaking from a continue loop), but `in_prompt_msg(raise_on_err=True)`
was changed to raise `ValueError`; so instead just use as a predicate
for the `break`.

Also rework `in_prompt_msg()` to accept the `child: BaseSpawn` as input
instead of `before: str` remove the casting boilerplate, and adjust all
usage to match.
multihost_exs
Tyler Goodlet 2024-07-12 15:57:41 -04:00
parent f7469442e3
commit 1f1a3f19d5
4 changed files with 71 additions and 73 deletions

View File

@ -25,7 +25,8 @@ async def main():
""" """
async with tractor.open_nursery( async with tractor.open_nursery(
debug_mode=True, debug_mode=True,
loglevel='cancel', # loglevel='cancel',
# loglevel='devx',
) as n: ) as n:
p0 = await n.start_actor('bp_forever', enable_modules=[__name__]) p0 = await n.start_actor('bp_forever', enable_modules=[__name__])

View File

@ -10,6 +10,7 @@ import pytest
from pexpect.exceptions import ( from pexpect.exceptions import (
TIMEOUT, TIMEOUT,
) )
from pexpect.spawnbase import SpawnBase
from tractor._testing import ( from tractor._testing import (
mk_cmd, mk_cmd,
) )
@ -107,7 +108,7 @@ def expect(
def in_prompt_msg( def in_prompt_msg(
prompt: str, child: SpawnBase,
parts: list[str], parts: list[str],
pause_on_false: bool = False, pause_on_false: bool = False,
@ -125,18 +126,20 @@ def in_prompt_msg(
''' '''
__tracebackhide__: bool = False __tracebackhide__: bool = False
before: str = str(child.before.decode())
for part in parts: for part in parts:
if part not in prompt: if part not in before:
if pause_on_false: if pause_on_false:
import pdbp import pdbp
pdbp.set_trace() pdbp.set_trace()
if print_prompt_on_false: if print_prompt_on_false:
print(prompt) print(before)
if err_on_false: if err_on_false:
raise ValueError( raise ValueError(
f'Could not find pattern: {part!r} in `before` output?' f'Could not find pattern in `before` output?\n'
f'part: {part!r}\n'
) )
return False return False
@ -147,7 +150,7 @@ def in_prompt_msg(
# against call stack frame output from the the 'll' command the like! # against call stack frame output from the the 'll' command the like!
# -[ ] SO answer for stipping ANSI codes: https://stackoverflow.com/a/14693789 # -[ ] SO answer for stipping ANSI codes: https://stackoverflow.com/a/14693789
def assert_before( def assert_before(
child, child: SpawnBase,
patts: list[str], patts: list[str],
**kwargs, **kwargs,
@ -155,10 +158,8 @@ def assert_before(
) -> None: ) -> None:
__tracebackhide__: bool = False __tracebackhide__: bool = False
# as in before the prompt end
before: str = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
prompt=before, child=child,
parts=patts, parts=patts,
# since this is an "assert" helper ;) # since this is an "assert" helper ;)

View File

@ -96,14 +96,15 @@ def test_root_actor_error(
# scan for the prompt # scan for the prompt
expect(child, PROMPT) expect(child, PROMPT)
before = str(child.before.decode())
# make sure expected logging and error arrives # make sure expected logging and error arrives
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_crash_msg, "('root'"] [
_crash_msg,
"('root'",
'AssertionError',
]
) )
assert 'AssertionError' in before
# send user command # send user command
child.sendline(user_input) child.sendline(user_input)
@ -243,10 +244,12 @@ def test_subactor_error(
# scan for the prompt # scan for the prompt
child.expect(PROMPT) child.expect(PROMPT)
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_crash_msg, "('name_error'"] [
_crash_msg,
"('name_error'",
]
) )
if do_next: if do_next:
@ -265,17 +268,15 @@ def test_subactor_error(
child.sendline('continue') child.sendline('continue')
child.expect(PROMPT) child.expect(PROMPT)
before = str(child.before.decode()) assert in_prompt_msg(
child,
[
_crash_msg,
# root actor gets debugger engaged # root actor gets debugger engaged
assert in_prompt_msg( "('root'",
before,
[_crash_msg, "('root'"]
)
# error is a remote error propagated from the subactor # error is a remote error propagated from the subactor
assert in_prompt_msg( "('name_error'",
before, ]
[_crash_msg, "('name_error'"]
) )
# another round # another round
@ -296,14 +297,11 @@ def test_subactor_breakpoint(
"Single subactor with an infinite breakpoint loop" "Single subactor with an infinite breakpoint loop"
child = spawn('subactor_breakpoint') child = spawn('subactor_breakpoint')
# scan for the prompt
child.expect(PROMPT) child.expect(PROMPT)
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_pause_msg, "('breakpoint_forever'"] [_pause_msg,
"('breakpoint_forever'",]
) )
# do some "next" commands to demonstrate recurrent breakpoint # do some "next" commands to demonstrate recurrent breakpoint
@ -319,9 +317,8 @@ def test_subactor_breakpoint(
for _ in range(5): for _ in range(5):
child.sendline('continue') child.sendline('continue')
child.expect(PROMPT) child.expect(PROMPT)
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_pause_msg, "('breakpoint_forever'"] [_pause_msg, "('breakpoint_forever'"]
) )
@ -334,9 +331,8 @@ def test_subactor_breakpoint(
# child process should exit but parent will capture pdb.BdbQuit # child process should exit but parent will capture pdb.BdbQuit
child.expect(PROMPT) child.expect(PROMPT)
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
['RemoteActorError:', ['RemoteActorError:',
"('breakpoint_forever'", "('breakpoint_forever'",
'bdb.BdbQuit',] 'bdb.BdbQuit',]
@ -351,9 +347,8 @@ def test_subactor_breakpoint(
# process should exit # process should exit
child.expect(EOF) child.expect(EOF)
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
['RemoteActorError:', ['RemoteActorError:',
"('breakpoint_forever'", "('breakpoint_forever'",
'bdb.BdbQuit',] 'bdb.BdbQuit',]
@ -377,7 +372,7 @@ def test_multi_subactors(
before = str(child.before.decode()) before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_pause_msg, "('breakpoint_forever'"] [_pause_msg, "('breakpoint_forever'"]
) )
@ -398,12 +393,14 @@ def test_multi_subactors(
# first name_error failure # first name_error failure
child.expect(PROMPT) child.expect(PROMPT)
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_crash_msg, "('name_error'"] [
_crash_msg,
"('name_error'",
"NameError",
]
) )
assert "NameError" in before
if ctlc: if ctlc:
do_ctlc(child) do_ctlc(child)
@ -427,9 +424,8 @@ def test_multi_subactors(
# breakpoint loop should re-engage # breakpoint loop should re-engage
child.sendline('c') child.sendline('c')
child.expect(PROMPT) child.expect(PROMPT)
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_pause_msg, "('breakpoint_forever'"] [_pause_msg, "('breakpoint_forever'"]
) )
@ -522,25 +518,28 @@ def test_multi_daemon_subactors(
# the root's tty lock first so anticipate either crash # the root's tty lock first so anticipate either crash
# message on the first entry. # message on the first entry.
bp_forev_parts = [_pause_msg, "('bp_forever'"] bp_forev_parts = [
_pause_msg,
"('bp_forever'",
]
bp_forev_in_msg = partial( bp_forev_in_msg = partial(
in_prompt_msg, in_prompt_msg,
parts=bp_forev_parts, parts=bp_forev_parts,
) )
name_error_msg = "NameError: name 'doggypants' is not defined" name_error_msg: str = "NameError: name 'doggypants' is not defined"
name_error_parts = [name_error_msg] name_error_parts: list[str] = [name_error_msg]
before = str(child.before.decode()) before = str(child.before.decode())
if bp_forev_in_msg(prompt=before): if bp_forev_in_msg(child=child):
next_parts = name_error_parts next_parts = name_error_parts
elif name_error_msg in before: elif name_error_msg in before:
next_parts = bp_forev_parts next_parts = bp_forev_parts
else: else:
raise ValueError("Neither log msg was found !?") raise ValueError('Neither log msg was found !?')
if ctlc: if ctlc:
do_ctlc(child) do_ctlc(child)
@ -609,14 +608,12 @@ def test_multi_daemon_subactors(
# wait for final error in root # wait for final error in root
# where it crashs with boxed error # where it crashs with boxed error
while True: while True:
try:
child.sendline('c') child.sendline('c')
child.expect(PROMPT) child.expect(PROMPT)
assert_before( if not in_prompt_msg(
child, child,
bp_forev_parts bp_forev_parts
) ):
except AssertionError:
break break
assert_before( assert_before(
@ -797,10 +794,13 @@ def test_root_nursery_cancels_before_child_releases_tty_lock(
child = spawn('root_cancelled_but_child_is_in_tty_lock') child = spawn('root_cancelled_but_child_is_in_tty_lock')
child.expect(PROMPT) child.expect(PROMPT)
assert_before(
before = str(child.before.decode()) child,
assert "NameError: name 'doggypants' is not defined" in before [
assert "tractor._exceptions.RemoteActorError: ('name_error'" not in before "NameError: name 'doggypants' is not defined",
"tractor._exceptions.RemoteActorError: ('name_error'",
],
)
time.sleep(0.5) time.sleep(0.5)
if ctlc: if ctlc:
@ -891,9 +891,8 @@ def test_different_debug_mode_per_actor(
child.expect(PROMPT) child.expect(PROMPT)
# only one actor should enter the debugger # only one actor should enter the debugger
before = str(child.before.decode())
assert in_prompt_msg( assert in_prompt_msg(
before, child,
[_crash_msg, "('debugged_boi'", "RuntimeError"], [_crash_msg, "('debugged_boi'", "RuntimeError"],
) )
@ -903,8 +902,6 @@ def test_different_debug_mode_per_actor(
child.sendline('c') child.sendline('c')
child.expect(EOF) child.expect(EOF)
before = str(child.before.decode())
# NOTE: this debugged actor error currently WON'T show up since the # NOTE: this debugged actor error currently WON'T show up since the
# root will actually cancel and terminate the nursery before the error # root will actually cancel and terminate the nursery before the error
# msg reported back from the debug mode actor is processed. # msg reported back from the debug mode actor is processed.
@ -956,9 +953,8 @@ def test_pause_from_sync(
child.expect(PROMPT) child.expect(PROMPT)
# XXX shouldn't see gb loaded message with PDB loglevel! # XXX shouldn't see gb loaded message with PDB loglevel!
before = str(child.before.decode())
assert not in_prompt_msg( assert not in_prompt_msg(
before, child,
['`greenback` portal opened!'], ['`greenback` portal opened!'],
) )
# should be same root task # should be same root task
@ -1039,7 +1035,7 @@ def test_pause_from_sync(
# at the same time as the one that was detected above. # at the same time as the one that was detected above.
for key, other_patts in attach_patts.copy().items(): for key, other_patts in attach_patts.copy().items():
assert not in_prompt_msg( assert not in_prompt_msg(
before, child,
other_patts, other_patts,
) )

View File

@ -291,7 +291,7 @@ def test_context_spawns_aio_task_that_errors(
err = excinfo.value err = excinfo.value
assert isinstance(err, expect) assert isinstance(err, expect)
assert err.boxed_type == AssertionError assert err.boxed_type is AssertionError
async def aio_cancel(): async def aio_cancel():
@ -497,7 +497,7 @@ def test_trio_error_cancels_intertask_chan(reg_addr):
trio.run(main) trio.run(main)
# ensure boxed error type # ensure boxed error type
excinfo.value.boxed_type == Exception excinfo.value.boxed_type is Exception
def test_trio_closes_early_and_channel_exits(reg_addr): def test_trio_closes_early_and_channel_exits(reg_addr):
@ -533,7 +533,7 @@ def test_aio_errors_and_channel_propagates_and_closes(reg_addr):
) as excinfo: ) as excinfo:
trio.run(main) trio.run(main)
excinfo.value.boxed_type == Exception excinfo.value.boxed_type is Exception
@tractor.context @tractor.context