From abd3cefd845ac2600fe8420bf67cd5f517bc7fea Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Sun, 28 May 2023 14:28:56 -0400 Subject: [PATCH] Parametrize ems service test to cancel with API and kbi --- tests/test_ems.py | 7 ++- tests/test_services.py | 120 +++++++++++++++++++++++++++++++---------- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/tests/test_ems.py b/tests/test_ems.py index 8ee99807..f9c010f0 100644 --- a/tests/test_ems.py +++ b/tests/test_ems.py @@ -20,7 +20,6 @@ from typing import ( ) import trio -# import pytest_trio from exceptiongroup import BaseExceptionGroup import pytest @@ -50,6 +49,7 @@ from piker.accounting import ( log = get_logger(__name__) + async def order_and_and_wait_for_ppmsg( client: OrderClient, trades_stream: tractor.MsgStream, @@ -370,7 +370,10 @@ def test_multi_fill_positions( run_and_tollerate_cancels(atest) - if check_cross_session or accum_size != 0: + if ( + check_cross_session + or accum_size != 0 + ): # rerun just to check that position info is persistent for the paper # account (i.e. a user can expect to see paper pps persist across # runtime sessions. diff --git a/tests/test_services.py b/tests/test_services.py index 6f7b6f4c..433e97f3 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -2,9 +2,13 @@ Actor tree daemon sub-service verifications ''' -from typing import AsyncContextManager +from typing import ( + AsyncContextManager, + Callable, +) from contextlib import asynccontextmanager as acm +from exceptiongroup import BaseExceptionGroup import pytest import trio import tractor @@ -61,24 +65,10 @@ def test_runtime_boot( trio.run(main) -@acm -async def ensure_service( - name: str, - sockaddr: tuple[str, int] | None = None, -) -> None: - async with find_service(name) as portal: - remote_sockaddr = portal.channel.raddr - print(f'FOUND `{name}` @ {remote_sockaddr}') - - if sockaddr: - assert remote_sockaddr == sockaddr - - yield portal - - def test_ensure_datafeed_actors( open_test_pikerd: AsyncContextManager, loglevel: str, + # cancel_method: str, ) -> None: ''' @@ -94,6 +84,7 @@ def test_ensure_datafeed_actors( async def main(): async with ( open_test_pikerd(), + open_feed( ['xbtusdt.kraken'], loglevel=loglevel, @@ -106,15 +97,89 @@ def test_ensure_datafeed_actors( ensure_service(brokerd_name), ensure_service('samplerd'), ): - pass + await trio.sleep(0.1) trio.run(main) +@acm +async def ensure_service( + name: str, + sockaddr: tuple[str, int] | None = None, +) -> None: + async with find_service(name) as portal: + remote_sockaddr = portal.channel.raddr + print(f'FOUND `{name}` @ {remote_sockaddr}') + + if sockaddr: + assert remote_sockaddr == sockaddr + + yield portal + + +def run_test_w_cancel_method( + cancel_method: str, + main: Callable, + +) -> None: + ''' + Run our runtime under trio and expect a certain type of cancel condition + depending on input. + + ''' + cancelled_msg: str = ( + "was remotely cancelled by remote actor (\'pikerd\'") + + if cancel_method == 'sigint': + with pytest.raises( + BaseExceptionGroup, + ) as exc_info: + trio.run(main) + + multi = exc_info.value + + for suberr in multi.exceptions: + match suberr: + # ensure we receive a remote cancellation error caused + # by the pikerd root actor since we used the + # `.cancel_service()` API above B) + case tractor.ContextCancelled(): + assert cancelled_msg in suberr.args[0] + + case KeyboardInterrupt(): + pass + + case _: + pytest.fail(f'Unexpected error {suberr}') + + elif cancel_method == 'services': + + # XXX NOTE: oddly, when you pass --pdb to pytest, i think since + # we also use that to enable the underlying tractor debug mode, + # it causes this to not raise for some reason? So if you see + # that while changing this test.. it's prolly that. + + with pytest.raises( + tractor.ContextCancelled + ) as exc_info: + trio.run(main) + + assert cancelled_msg in exc_info.value.args[0] + + else: + pytest.fail(f'Test is broken due to {cancel_method}') + + +@pytest.mark.parametrize( + 'cancel_method', + ['services', 'sigint'], +) def test_ensure_ems_in_paper_actors( open_test_pikerd: AsyncContextManager, loglevel: str, + cancel_method: str, + ) -> None: actor_name: str = 'brokerd' @@ -153,7 +218,7 @@ def test_ensure_ems_in_paper_actors( # local ledger and `pps.toml` state ;) assert not pps assert not dialogs - + # XXX: should be new client with no state from other tests assert not client._sent_orders assert accounts @@ -171,16 +236,13 @@ def test_ensure_ems_in_paper_actors( # implicitly by the ems. assert brokerd_name in services.service_tasks - print('ALL SERVICES STARTED, terminating..') - await services.cancel_service('emsd') + print('ALL SERVICES STARTED, cancelling runtime with:\n' + f'-> {cancel_method}') - # ensure we receive a remote cancellation error caused by the - # pikerd root actor since we used the `.cancel_service()` API - # above B) - with pytest.raises( - tractor._exceptions.ContextCancelled, - ) as exc_info: - trio.run(main) + if cancel_method == 'services': + await services.cancel_service('emsd') - cancelled_msg: str = "was remotely cancelled by remote actor (\'pikerd\'" - assert cancelled_msg in exc_info.value.args[0] + elif cancel_method == 'sigint': + raise KeyboardInterrupt + + run_test_w_cancel_method(cancel_method, main)