Dynamically set `pld_spec` for `test_basic_payload_spec()
Such that we can parametrize the `@context(pld_spec)` endpoint setting using `pytest` and of course enable testing more then just the lone `maybe_msg_spec` case. The implementation was a bit tricky because subactors import any `enable_modules` just after subproc spawn, so there's no easy way to indicate from the parent should should be passed to the `@context()` decorator since it's already resolved by the time an IPC is established. Thus the bulk of this patch is implementing a pre-ctx which monkey-patches the (test) `child()`-ep-defining-module before running test logic. Impl deats, - drop `maybe_msg_spec` global instead providing the same value via a new `pld_spec: Union[Type]` parametrized input to the test suite. - add a `decorate_child_ep()` helper which (re-)decorates the mod-defined `child()` IPC-context endpoint with the provided `pld_spec`. - add a new "pre IPC context" endpoint: `set_chld_pldspec()` which can be opened (from another actor) just prior to opening the `child()` ep and it will decorate the latter (using `decorate_child_ep()`) presuming a `.msg._exts.enc_type_union()` generated `pld_spec_strs` is provided. - actually open the `set_chld_pldspec()` as a `deco_ctx` rom the root-actor and ensure we cancel it on block teardown in non-raising cases.pld_dec_refinements
parent
7d947d3776
commit
ccedee3b87
|
@ -7,6 +7,12 @@ related settings around IPC contexts.
|
|||
from contextlib import (
|
||||
asynccontextmanager as acm,
|
||||
)
|
||||
import sys
|
||||
import types
|
||||
from typing import (
|
||||
Union,
|
||||
Type,
|
||||
)
|
||||
|
||||
from msgspec import (
|
||||
Struct,
|
||||
|
@ -22,11 +28,10 @@ from tractor import (
|
|||
Portal,
|
||||
)
|
||||
from tractor.msg import (
|
||||
_codec,
|
||||
_ops as msgops,
|
||||
Return,
|
||||
)
|
||||
from tractor.msg import (
|
||||
_codec,
|
||||
_exts,
|
||||
)
|
||||
from tractor.msg.types import (
|
||||
log,
|
||||
|
@ -47,9 +52,6 @@ class PldMsg(
|
|||
field: str
|
||||
|
||||
|
||||
maybe_msg_spec = PldMsg|None
|
||||
|
||||
|
||||
@acm
|
||||
async def maybe_expect_raises(
|
||||
raises: BaseException|None = None,
|
||||
|
@ -104,9 +106,15 @@ async def maybe_expect_raises(
|
|||
)
|
||||
|
||||
|
||||
@tractor.context(
|
||||
pld_spec=maybe_msg_spec,
|
||||
)
|
||||
# NOTE, this decorator is applied dynamically by both the root and
|
||||
# 'sub' actor such that we can dynamically apply various cases from
|
||||
# a parametrized test.
|
||||
#
|
||||
# maybe_msg_spec = PldMsg|None
|
||||
#
|
||||
# @tractor.context(
|
||||
# pld_spec=maybe_msg_spec,
|
||||
# )
|
||||
async def child(
|
||||
ctx: Context,
|
||||
started_value: int|PldMsg|None,
|
||||
|
@ -219,6 +227,48 @@ async def child(
|
|||
# msg-type-error from this RPC task ;)
|
||||
return return_value
|
||||
|
||||
def decorate_child_ep(
|
||||
pld_spec: Union[Type],
|
||||
) -> types.ModuleType:
|
||||
'''
|
||||
Apply parametrized pld_spec to ctx ep like,
|
||||
|
||||
@tractor.context(
|
||||
pld_spec=maybe_msg_spec,
|
||||
)(child)
|
||||
|
||||
'''
|
||||
this_mod = sys.modules[__name__]
|
||||
global child # a mod-fn defined above
|
||||
assert this_mod.child is child
|
||||
this_mod.child = tractor.context(
|
||||
pld_spec=pld_spec,
|
||||
)(child)
|
||||
return this_mod
|
||||
|
||||
|
||||
@tractor.context
|
||||
async def set_chld_pldspec(
|
||||
ctx: tractor.Context,
|
||||
pld_spec_strs: list[str],
|
||||
):
|
||||
'''
|
||||
Dynamically apply the `@context(pld_spec=pld_spec)` deco to the
|
||||
current actor's in-mem instance of this test module.
|
||||
|
||||
Allows dynamically applying the "payload-spec" in both a parent
|
||||
and child actor after spawn.
|
||||
|
||||
'''
|
||||
this_mod = sys.modules[__name__]
|
||||
pld_spec: list[str] = _exts.dec_type_union(
|
||||
pld_spec_strs,
|
||||
mods=[this_mod],
|
||||
)
|
||||
decorate_child_ep(pld_spec)
|
||||
await ctx.started()
|
||||
await trio.sleep_forever()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'return_value',
|
||||
|
@ -253,12 +303,25 @@ async def child(
|
|||
'no-started-pld-validate',
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
'pld_spec',
|
||||
[
|
||||
PldMsg|None,
|
||||
# !TODO, these cases
|
||||
# Msg1|Msg2|None,
|
||||
# Msg1|Msg2|Any,
|
||||
],
|
||||
ids=[
|
||||
'maybe_PldMsg_spec',
|
||||
]
|
||||
)
|
||||
def test_basic_payload_spec(
|
||||
debug_mode: bool,
|
||||
loglevel: str,
|
||||
return_value: str|None,
|
||||
started_value: int|PldMsg,
|
||||
pld_check_started_value: bool,
|
||||
pld_spec: Union[Type],
|
||||
):
|
||||
'''
|
||||
Validate the most basic `PldRx` msg-type-spec semantics around
|
||||
|
@ -270,13 +333,24 @@ def test_basic_payload_spec(
|
|||
invalid_return: bool = return_value == 'yo'
|
||||
invalid_started: bool = started_value == 10
|
||||
|
||||
# dynamically apply ep's pld-spec in 'root'.
|
||||
decorate_child_ep(pld_spec)
|
||||
assert (
|
||||
child._tractor_context_meta['pld_spec'] == pld_spec
|
||||
)
|
||||
pld_types: set[Type] = _codec.unpack_spec_types(pld_spec)
|
||||
pld_spec_strs: list[str] = _exts.enc_type_union(
|
||||
pld_spec,
|
||||
)
|
||||
assert len(pld_types) > 1
|
||||
|
||||
async def main():
|
||||
async with tractor.open_nursery(
|
||||
debug_mode=debug_mode,
|
||||
loglevel=loglevel,
|
||||
) as an:
|
||||
p: Portal = await an.start_actor(
|
||||
'child',
|
||||
'sub',
|
||||
enable_modules=[__name__],
|
||||
)
|
||||
|
||||
|
@ -286,9 +360,11 @@ def test_basic_payload_spec(
|
|||
if invalid_started:
|
||||
msg_type_str: str = 'Started'
|
||||
bad_value: int = 10
|
||||
|
||||
elif invalid_return:
|
||||
msg_type_str: str = 'Return'
|
||||
bad_value: str = 'yo'
|
||||
|
||||
else:
|
||||
# XXX but should never be used below then..
|
||||
msg_type_str: str = ''
|
||||
|
@ -302,6 +378,7 @@ def test_basic_payload_spec(
|
|||
invalid_started
|
||||
) else None
|
||||
)
|
||||
|
||||
async with (
|
||||
maybe_expect_raises(
|
||||
raises=should_raise,
|
||||
|
@ -315,6 +392,11 @@ def test_basic_payload_spec(
|
|||
# only for debug
|
||||
# post_mortem=True,
|
||||
),
|
||||
p.open_context(
|
||||
set_chld_pldspec,
|
||||
pld_spec_strs=pld_spec_strs,
|
||||
) as (deco_ctx, _),
|
||||
|
||||
p.open_context(
|
||||
child,
|
||||
return_value=return_value,
|
||||
|
@ -356,6 +438,9 @@ def test_basic_payload_spec(
|
|||
ctx.outcome
|
||||
)
|
||||
|
||||
if should_raise is None:
|
||||
await deco_ctx.cancel()
|
||||
|
||||
if should_raise is None:
|
||||
assert maybe_mte is None
|
||||
|
||||
|
|
Loading…
Reference in New Issue