forked from goodboy/tractor
				
			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.remotes/1757153874605917753/main
							parent
							
								
									8da7a1ca36
								
							
						
					
					
						commit
						00d1c8ea29
					
				|  | @ -25,7 +25,8 @@ async def main(): | |||
|     """ | ||||
|     async with tractor.open_nursery( | ||||
|         debug_mode=True, | ||||
|         loglevel='cancel', | ||||
|         # loglevel='cancel', | ||||
|         # loglevel='devx', | ||||
|     ) as n: | ||||
| 
 | ||||
|         p0 = await n.start_actor('bp_forever', enable_modules=[__name__]) | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ import pytest | |||
| from pexpect.exceptions import ( | ||||
|     TIMEOUT, | ||||
| ) | ||||
| from pexpect.spawnbase import SpawnBase | ||||
| from tractor._testing import ( | ||||
|     mk_cmd, | ||||
| ) | ||||
|  | @ -107,7 +108,7 @@ def expect( | |||
| 
 | ||||
| 
 | ||||
| def in_prompt_msg( | ||||
|     prompt: str, | ||||
|     child: SpawnBase, | ||||
|     parts: list[str], | ||||
| 
 | ||||
|     pause_on_false: bool = False, | ||||
|  | @ -125,18 +126,20 @@ def in_prompt_msg( | |||
|     ''' | ||||
|     __tracebackhide__: bool = False | ||||
| 
 | ||||
|     before: str = str(child.before.decode()) | ||||
|     for part in parts: | ||||
|         if part not in prompt: | ||||
|         if part not in before: | ||||
|             if pause_on_false: | ||||
|                 import pdbp | ||||
|                 pdbp.set_trace() | ||||
| 
 | ||||
|             if print_prompt_on_false: | ||||
|                 print(prompt) | ||||
|                 print(before) | ||||
| 
 | ||||
|             if err_on_false: | ||||
|                 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 | ||||
| 
 | ||||
|  | @ -147,7 +150,7 @@ def in_prompt_msg( | |||
| # against call stack frame output from the the 'll' command the like! | ||||
| # -[ ] SO answer for stipping ANSI codes: https://stackoverflow.com/a/14693789 | ||||
| def assert_before( | ||||
|     child, | ||||
|     child: SpawnBase, | ||||
|     patts: list[str], | ||||
| 
 | ||||
|     **kwargs, | ||||
|  | @ -155,10 +158,8 @@ def assert_before( | |||
| ) -> None: | ||||
|     __tracebackhide__: bool = False | ||||
| 
 | ||||
|     # as in before the prompt end | ||||
|     before: str = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         prompt=before, | ||||
|         child=child, | ||||
|         parts=patts, | ||||
| 
 | ||||
|         # since this is an "assert" helper ;) | ||||
|  |  | |||
|  | @ -94,14 +94,15 @@ def test_root_actor_error( | |||
|     # scan for the prompt | ||||
|     expect(child, PROMPT) | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
| 
 | ||||
|     # make sure expected logging and error arrives | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         [_crash_msg, "('root'"] | ||||
|         child, | ||||
|         [ | ||||
|             _crash_msg, | ||||
|             "('root'", | ||||
|             'AssertionError', | ||||
|         ] | ||||
|     ) | ||||
|     assert 'AssertionError' in before | ||||
| 
 | ||||
|     # send user command | ||||
|     child.sendline(user_input) | ||||
|  | @ -241,10 +242,12 @@ def test_subactor_error( | |||
|     # scan for the prompt | ||||
|     child.expect(PROMPT) | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         [_crash_msg, "('name_error'"] | ||||
|         child, | ||||
|         [ | ||||
|             _crash_msg, | ||||
|             "('name_error'", | ||||
|         ] | ||||
|     ) | ||||
| 
 | ||||
|     if do_next: | ||||
|  | @ -263,17 +266,15 @@ def test_subactor_error( | |||
|         child.sendline('continue') | ||||
| 
 | ||||
|     child.expect(PROMPT) | ||||
|     before = str(child.before.decode()) | ||||
| 
 | ||||
|     # root actor gets debugger engaged | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         [_crash_msg, "('root'"] | ||||
|     ) | ||||
|     # error is a remote error propagated from the subactor | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         [_crash_msg, "('name_error'"] | ||||
|         child, | ||||
|         [ | ||||
|             _crash_msg, | ||||
|             # root actor gets debugger engaged | ||||
|             "('root'", | ||||
|             # error is a remote error propagated from the subactor | ||||
|             "('name_error'", | ||||
|         ] | ||||
|     ) | ||||
| 
 | ||||
|     # another round | ||||
|  | @ -294,14 +295,11 @@ def test_subactor_breakpoint( | |||
|     "Single subactor with an infinite breakpoint loop" | ||||
| 
 | ||||
|     child = spawn('subactor_breakpoint') | ||||
| 
 | ||||
|     # scan for the prompt | ||||
|     child.expect(PROMPT) | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         [_pause_msg, "('breakpoint_forever'"] | ||||
|         child, | ||||
|         [_pause_msg, | ||||
|          "('breakpoint_forever'",] | ||||
|     ) | ||||
| 
 | ||||
|     # do some "next" commands to demonstrate recurrent breakpoint | ||||
|  | @ -317,9 +315,8 @@ def test_subactor_breakpoint( | |||
|     for _ in range(5): | ||||
|         child.sendline('continue') | ||||
|         child.expect(PROMPT) | ||||
|         before = str(child.before.decode()) | ||||
|         assert in_prompt_msg( | ||||
|             before, | ||||
|             child, | ||||
|             [_pause_msg, "('breakpoint_forever'"] | ||||
|         ) | ||||
| 
 | ||||
|  | @ -332,9 +329,8 @@ def test_subactor_breakpoint( | |||
|     # child process should exit but parent will capture pdb.BdbQuit | ||||
|     child.expect(PROMPT) | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         child, | ||||
|         ['RemoteActorError:', | ||||
|          "('breakpoint_forever'", | ||||
|          'bdb.BdbQuit',] | ||||
|  | @ -349,9 +345,8 @@ def test_subactor_breakpoint( | |||
|     # process should exit | ||||
|     child.expect(EOF) | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         child, | ||||
|         ['RemoteActorError:', | ||||
|          "('breakpoint_forever'", | ||||
|          'bdb.BdbQuit',] | ||||
|  | @ -375,7 +370,7 @@ def test_multi_subactors( | |||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         child, | ||||
|         [_pause_msg, "('breakpoint_forever'"] | ||||
|     ) | ||||
| 
 | ||||
|  | @ -396,12 +391,14 @@ def test_multi_subactors( | |||
| 
 | ||||
|     # first name_error failure | ||||
|     child.expect(PROMPT) | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         [_crash_msg, "('name_error'"] | ||||
|         child, | ||||
|         [ | ||||
|             _crash_msg, | ||||
|             "('name_error'", | ||||
|             "NameError", | ||||
|         ] | ||||
|     ) | ||||
|     assert "NameError" in before | ||||
| 
 | ||||
|     if ctlc: | ||||
|         do_ctlc(child) | ||||
|  | @ -425,9 +422,8 @@ def test_multi_subactors( | |||
|     # breakpoint loop should re-engage | ||||
|     child.sendline('c') | ||||
|     child.expect(PROMPT) | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         child, | ||||
|         [_pause_msg, "('breakpoint_forever'"] | ||||
|     ) | ||||
| 
 | ||||
|  | @ -520,25 +516,28 @@ def test_multi_daemon_subactors( | |||
|     # the root's tty lock first so anticipate either crash | ||||
|     # message on the first entry. | ||||
| 
 | ||||
|     bp_forev_parts = [_pause_msg, "('bp_forever'"] | ||||
|     bp_forev_parts = [ | ||||
|         _pause_msg, | ||||
|         "('bp_forever'", | ||||
|     ] | ||||
|     bp_forev_in_msg = partial( | ||||
|         in_prompt_msg, | ||||
|         parts=bp_forev_parts, | ||||
|     ) | ||||
| 
 | ||||
|     name_error_msg = "NameError: name 'doggypants' is not defined" | ||||
|     name_error_parts = [name_error_msg] | ||||
|     name_error_msg: str = "NameError: name 'doggypants' is not defined" | ||||
|     name_error_parts: list[str] = [name_error_msg] | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
| 
 | ||||
|     if bp_forev_in_msg(prompt=before): | ||||
|     if bp_forev_in_msg(child=child): | ||||
|         next_parts = name_error_parts | ||||
| 
 | ||||
|     elif name_error_msg in before: | ||||
|         next_parts = bp_forev_parts | ||||
| 
 | ||||
|     else: | ||||
|         raise ValueError("Neither log msg was found !?") | ||||
|         raise ValueError('Neither log msg was found !?') | ||||
| 
 | ||||
|     if ctlc: | ||||
|         do_ctlc(child) | ||||
|  | @ -607,14 +606,12 @@ def test_multi_daemon_subactors( | |||
|     # wait for final error in root | ||||
|     # where it crashs with boxed error | ||||
|     while True: | ||||
|         try: | ||||
|             child.sendline('c') | ||||
|             child.expect(PROMPT) | ||||
|             assert_before( | ||||
|                 child, | ||||
|                 bp_forev_parts | ||||
|             ) | ||||
|         except AssertionError: | ||||
|         child.sendline('c') | ||||
|         child.expect(PROMPT) | ||||
|         if not in_prompt_msg( | ||||
|             child, | ||||
|             bp_forev_parts | ||||
|         ): | ||||
|             break | ||||
| 
 | ||||
|     assert_before( | ||||
|  | @ -795,10 +792,13 @@ def test_root_nursery_cancels_before_child_releases_tty_lock( | |||
|     child = spawn('root_cancelled_but_child_is_in_tty_lock') | ||||
| 
 | ||||
|     child.expect(PROMPT) | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
|     assert "NameError: name 'doggypants' is not defined" in before | ||||
|     assert "tractor._exceptions.RemoteActorError: ('name_error'" not in before | ||||
|     assert_before( | ||||
|         child, | ||||
|         [ | ||||
|             "NameError: name 'doggypants' is not defined", | ||||
|             "tractor._exceptions.RemoteActorError: ('name_error'", | ||||
|         ], | ||||
|     ) | ||||
|     time.sleep(0.5) | ||||
| 
 | ||||
|     if ctlc: | ||||
|  | @ -889,9 +889,8 @@ def test_different_debug_mode_per_actor( | |||
|     child.expect(PROMPT) | ||||
| 
 | ||||
|     # only one actor should enter the debugger | ||||
|     before = str(child.before.decode()) | ||||
|     assert in_prompt_msg( | ||||
|         before, | ||||
|         child, | ||||
|         [_crash_msg, "('debugged_boi'", "RuntimeError"], | ||||
|     ) | ||||
| 
 | ||||
|  | @ -901,8 +900,6 @@ def test_different_debug_mode_per_actor( | |||
|     child.sendline('c') | ||||
|     child.expect(EOF) | ||||
| 
 | ||||
|     before = str(child.before.decode()) | ||||
| 
 | ||||
|     # NOTE: this debugged actor error currently WON'T show up since the | ||||
|     # root will actually cancel and terminate the nursery before the error | ||||
|     # msg reported back from the debug mode actor is processed. | ||||
|  | @ -954,9 +951,8 @@ def test_pause_from_sync( | |||
|     child.expect(PROMPT) | ||||
| 
 | ||||
|     # XXX shouldn't see gb loaded message with PDB loglevel! | ||||
|     before = str(child.before.decode()) | ||||
|     assert not in_prompt_msg( | ||||
|         before, | ||||
|         child, | ||||
|         ['`greenback` portal opened!'], | ||||
|     ) | ||||
|     # should be same root task | ||||
|  | @ -1037,7 +1033,7 @@ def test_pause_from_sync( | |||
|         # at the same time as the one that was detected above. | ||||
|         for key, other_patts in attach_patts.copy().items(): | ||||
|             assert not in_prompt_msg( | ||||
|                 before, | ||||
|                 child, | ||||
|                 other_patts, | ||||
|             ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -291,7 +291,7 @@ def test_context_spawns_aio_task_that_errors( | |||
| 
 | ||||
|         err = excinfo.value | ||||
|         assert isinstance(err, expect) | ||||
|         assert err.boxed_type == AssertionError | ||||
|         assert err.boxed_type is AssertionError | ||||
| 
 | ||||
| 
 | ||||
| async def aio_cancel(): | ||||
|  | @ -497,7 +497,7 @@ def test_trio_error_cancels_intertask_chan(reg_addr): | |||
|         trio.run(main) | ||||
| 
 | ||||
|     # 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): | ||||
|  | @ -533,7 +533,7 @@ def test_aio_errors_and_channel_propagates_and_closes(reg_addr): | |||
|     ) as excinfo: | ||||
|         trio.run(main) | ||||
| 
 | ||||
|     excinfo.value.boxed_type == Exception | ||||
|     excinfo.value.boxed_type is Exception | ||||
| 
 | ||||
| 
 | ||||
| @tractor.context | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue