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
parent
f7469442e3
commit
1f1a3f19d5
|
@ -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__])
|
||||||
|
|
|
@ -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 ;)
|
||||||
|
|
|
@ -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())
|
|
||||||
|
|
||||||
# root actor gets debugger engaged
|
|
||||||
assert in_prompt_msg(
|
assert in_prompt_msg(
|
||||||
before,
|
child,
|
||||||
[_crash_msg, "('root'"]
|
[
|
||||||
)
|
_crash_msg,
|
||||||
# error is a remote error propagated from the subactor
|
# root actor gets debugger engaged
|
||||||
assert in_prompt_msg(
|
"('root'",
|
||||||
before,
|
# error is a remote error propagated from the subactor
|
||||||
[_crash_msg, "('name_error'"]
|
"('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)
|
if not in_prompt_msg(
|
||||||
assert_before(
|
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue