Add an `actorc` test-driven-dev suite
Defining how an actor-nursery should emit an eg based on non-graceful cancellation in a new `test_actor_nursery` module. Obviously fails atm until the implementation is completed.actor_cancelled_exc_type
							parent
							
								
									2dc13a3304
								
							
						
					
					
						commit
						28d6f77e22
					
				|  | @ -0,0 +1,98 @@ | |||
| ''' | ||||
| Basic `ActorNursery` operations and closure semantics, | ||||
| - basic remote error collection, | ||||
| - basic multi-subactor cancellation. | ||||
| 
 | ||||
| ''' | ||||
| # import os | ||||
| # import signal | ||||
| # import platform | ||||
| # import time | ||||
| # from itertools import repeat | ||||
| 
 | ||||
| import pytest | ||||
| import trio | ||||
| import tractor | ||||
| from tractor._exceptions import ActorCancelled | ||||
| # from tractor._testing import ( | ||||
| #     tractor_test, | ||||
| # ) | ||||
| # from .conftest import no_windows | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize( | ||||
|     'num_subs', | ||||
|     [ | ||||
|         1, | ||||
|         3, | ||||
|     ] | ||||
| ) | ||||
| def test_one_cancels_all( | ||||
|     start_method: str, | ||||
|     loglevel: str, | ||||
|     debug_mode: bool, | ||||
|     num_subs: int, | ||||
| ): | ||||
|     ''' | ||||
|     Verify that ifa a single error bubbles to the an-scope the | ||||
|     nursery will be cancelled (just like in `trio`); this is a | ||||
|     one-cancels-all style strategy and are only supervision policy | ||||
|     at the moment. | ||||
| 
 | ||||
|     ''' | ||||
|     async def main(): | ||||
|         try: | ||||
|             rte = RuntimeError('Uh oh something bad in parent') | ||||
|             async with tractor.open_nursery( | ||||
|                 start_method=start_method, | ||||
|                 loglevel=loglevel, | ||||
|                 debug_mode=debug_mode, | ||||
|             ) as an: | ||||
| 
 | ||||
|                 # spawn the same number of deamon actors which should be cancelled | ||||
|                 dactor_portals = [] | ||||
|                 for i in range(num_subs): | ||||
|                     name: str= f'sub_{i}' | ||||
|                     ptl: tractor.Portal = await an.start_actor( | ||||
|                         name=name, | ||||
|                         enable_modules=[__name__], | ||||
|                     ) | ||||
|                     dactor_portals.append(ptl) | ||||
| 
 | ||||
|                     # wait for booted | ||||
|                     async with tractor.wait_for_actor(name): | ||||
|                         print(f'{name!r} is up.') | ||||
| 
 | ||||
|                 # simulate uncaught exc | ||||
|                 raise rte | ||||
| 
 | ||||
|             # should error here with a ``RemoteActorError`` or ``MultiError`` | ||||
| 
 | ||||
|         except BaseExceptionGroup as _beg: | ||||
|             beg = _beg | ||||
| 
 | ||||
|             # ?TODO? why can't we do `is` on beg? | ||||
|             assert ( | ||||
|                 beg.exceptions | ||||
|                 == | ||||
|                 an.maybe_error.exceptions | ||||
|             ) | ||||
| 
 | ||||
|             assert len(beg.exceptions) == ( | ||||
|                 num_subs | ||||
|                 + | ||||
|                 1  # rte from root | ||||
|             ) | ||||
| 
 | ||||
|             # all subactors should have been implicitly | ||||
|             # `Portal.cancel_actor()`ed. | ||||
|             excs = list(beg.exceptions) | ||||
|             excs.remove(rte) | ||||
|             for exc in excs: | ||||
|                 assert isinstance(exc, ActorCancelled) | ||||
| 
 | ||||
|             assert an._scope_error is rte | ||||
|             assert not an._children | ||||
|             assert an.cancelled is True | ||||
| 
 | ||||
|     trio.run(main) | ||||
		Loading…
	
		Reference in New Issue