forked from goodboy/tractor
Update pld-rx limiting test(s) to use deco input
The tests only use one input spec (conveniently) so there's not much to change in the logic, - only pass the `maybe_msg_spec` to the child-side decorator and obvi drop the surrounding `msgops.limit_plds()` block in the child. - tweak a few `MsgDec` asserts, mostly dropping the `msg._ops._def_any_spec` state checks since the child-side won't have any pre pld-spec state given the runtime now applies the `pld_spec` before running the task's func body. - also allowed dropping the `finally:` which did a similar check outside the `.limit_plds()` block.runtime_to_msgspec
parent
04bd111037
commit
affc210033
|
@ -7,9 +7,6 @@ related settings around IPC contexts.
|
||||||
from contextlib import (
|
from contextlib import (
|
||||||
asynccontextmanager as acm,
|
asynccontextmanager as acm,
|
||||||
)
|
)
|
||||||
from contextvars import (
|
|
||||||
Context,
|
|
||||||
)
|
|
||||||
|
|
||||||
from msgspec import (
|
from msgspec import (
|
||||||
Struct,
|
Struct,
|
||||||
|
@ -19,6 +16,7 @@ import trio
|
||||||
|
|
||||||
import tractor
|
import tractor
|
||||||
from tractor import (
|
from tractor import (
|
||||||
|
Context,
|
||||||
MsgTypeError,
|
MsgTypeError,
|
||||||
current_ipc_ctx,
|
current_ipc_ctx,
|
||||||
Portal,
|
Portal,
|
||||||
|
@ -35,7 +33,17 @@ from tractor.msg.types import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PldMsg(Struct):
|
class PldMsg(
|
||||||
|
Struct,
|
||||||
|
|
||||||
|
# TODO: with multiple structs in-spec we need to tag them!
|
||||||
|
# -[ ] offer a built-in `PldMsg` type to inherit from which takes
|
||||||
|
# case of these details?
|
||||||
|
#
|
||||||
|
# https://jcristharif.com/msgspec/structs.html#tagged-unions
|
||||||
|
# tag=True,
|
||||||
|
# tag_field='msg_type',
|
||||||
|
):
|
||||||
field: str
|
field: str
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,12 +104,14 @@ async def maybe_expect_raises(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@tractor.context
|
@tractor.context(
|
||||||
|
pld_spec=maybe_msg_spec,
|
||||||
|
)
|
||||||
async def child(
|
async def child(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
started_value: int|PldMsg|None,
|
started_value: int|PldMsg|None,
|
||||||
return_value: str|None,
|
return_value: str|None,
|
||||||
validate_pld_spec: bool,
|
validate_pld_spec: bool,
|
||||||
raise_on_started_mte: bool = True,
|
raise_on_started_mte: bool = True,
|
||||||
|
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -116,113 +126,99 @@ async def child(
|
||||||
assert ctx is curr_ctx
|
assert ctx is curr_ctx
|
||||||
|
|
||||||
rx: msgops.PldRx = ctx._pld_rx
|
rx: msgops.PldRx = ctx._pld_rx
|
||||||
orig_pldec: _codec.MsgDec = rx.pld_dec
|
curr_pldec: _codec.MsgDec = rx.pld_dec
|
||||||
# senity that default pld-spec should be set
|
|
||||||
assert (
|
ctx_meta: dict = getattr(
|
||||||
rx.pld_dec
|
child,
|
||||||
is
|
'_tractor_context_meta',
|
||||||
msgops._def_any_pldec
|
None,
|
||||||
)
|
)
|
||||||
|
if ctx_meta:
|
||||||
|
assert (
|
||||||
|
ctx_meta['pld_spec']
|
||||||
|
is curr_pldec.spec
|
||||||
|
is curr_pldec.pld_spec
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2 cases: hdndle send-side and recv-only validation
|
||||||
|
# - when `raise_on_started_mte == True`, send validate
|
||||||
|
# - else, parent-recv-side only validation
|
||||||
|
mte: MsgTypeError|None = None
|
||||||
try:
|
try:
|
||||||
with msgops.limit_plds(
|
await ctx.started(
|
||||||
spec=maybe_msg_spec,
|
value=started_value,
|
||||||
) as pldec:
|
validate_pld_spec=validate_pld_spec,
|
||||||
# sanity on `MsgDec` state
|
)
|
||||||
assert rx.pld_dec is pldec
|
|
||||||
assert pldec.spec is maybe_msg_spec
|
|
||||||
|
|
||||||
# 2 cases: hdndle send-side and recv-only validation
|
except MsgTypeError as _mte:
|
||||||
# - when `raise_on_started_mte == True`, send validate
|
mte = _mte
|
||||||
# - else, parent-recv-side only validation
|
log.exception('started()` raised an MTE!\n')
|
||||||
mte: MsgTypeError|None = None
|
if not expect_started_mte:
|
||||||
try:
|
raise RuntimeError(
|
||||||
await ctx.started(
|
'Child-ctx-task SHOULD NOT HAVE raised an MTE for\n\n'
|
||||||
value=started_value,
|
f'{started_value!r}\n'
|
||||||
validate_pld_spec=validate_pld_spec,
|
|
||||||
)
|
|
||||||
|
|
||||||
except MsgTypeError as _mte:
|
|
||||||
mte = _mte
|
|
||||||
log.exception('started()` raised an MTE!\n')
|
|
||||||
if not expect_started_mte:
|
|
||||||
raise RuntimeError(
|
|
||||||
'Child-ctx-task SHOULD NOT HAVE raised an MTE for\n\n'
|
|
||||||
f'{started_value!r}\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
boxed_div: str = '------ - ------'
|
|
||||||
assert boxed_div not in mte._message
|
|
||||||
assert boxed_div not in mte.tb_str
|
|
||||||
assert boxed_div not in repr(mte)
|
|
||||||
assert boxed_div not in str(mte)
|
|
||||||
mte_repr: str = repr(mte)
|
|
||||||
for line in mte.message.splitlines():
|
|
||||||
assert line in mte_repr
|
|
||||||
|
|
||||||
# since this is a *local error* there should be no
|
|
||||||
# boxed traceback content!
|
|
||||||
assert not mte.tb_str
|
|
||||||
|
|
||||||
# propagate to parent?
|
|
||||||
if raise_on_started_mte:
|
|
||||||
raise
|
|
||||||
|
|
||||||
# no-send-side-error fallthrough
|
|
||||||
if (
|
|
||||||
validate_pld_spec
|
|
||||||
and
|
|
||||||
expect_started_mte
|
|
||||||
):
|
|
||||||
raise RuntimeError(
|
|
||||||
'Child-ctx-task SHOULD HAVE raised an MTE for\n\n'
|
|
||||||
f'{started_value!r}\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
assert (
|
|
||||||
not expect_started_mte
|
|
||||||
or
|
|
||||||
not validate_pld_spec
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# if wait_for_parent_to_cancel:
|
boxed_div: str = '------ - ------'
|
||||||
# ...
|
assert boxed_div not in mte._message
|
||||||
#
|
assert boxed_div not in mte.tb_str
|
||||||
# ^-TODO-^ logic for diff validation policies on each side:
|
assert boxed_div not in repr(mte)
|
||||||
#
|
assert boxed_div not in str(mte)
|
||||||
# -[ ] ensure that if we don't validate on the send
|
mte_repr: str = repr(mte)
|
||||||
# side, that we are eventually error-cancelled by our
|
for line in mte.message.splitlines():
|
||||||
# parent due to the bad `Started` payload!
|
assert line in mte_repr
|
||||||
# -[ ] the boxed error should be srced from the parent's
|
|
||||||
# runtime NOT ours!
|
|
||||||
# -[ ] we should still error on bad `return_value`s
|
|
||||||
# despite the parent not yet error-cancelling us?
|
|
||||||
# |_ how do we want the parent side to look in that
|
|
||||||
# case?
|
|
||||||
# -[ ] maybe the equiv of "during handling of the
|
|
||||||
# above error another occurred" for the case where
|
|
||||||
# the parent sends a MTE to this child and while
|
|
||||||
# waiting for the child to terminate it gets back
|
|
||||||
# the MTE for this case?
|
|
||||||
#
|
|
||||||
|
|
||||||
# XXX should always fail on recv side since we can't
|
# since this is a *local error* there should be no
|
||||||
# really do much else beside terminate and relay the
|
# boxed traceback content!
|
||||||
# msg-type-error from this RPC task ;)
|
assert not mte.tb_str
|
||||||
return return_value
|
|
||||||
|
|
||||||
finally:
|
# propagate to parent?
|
||||||
# sanity on `limit_plds()` reversion
|
if raise_on_started_mte:
|
||||||
assert (
|
raise
|
||||||
rx.pld_dec
|
|
||||||
is
|
# no-send-side-error fallthrough
|
||||||
msgops._def_any_pldec
|
if (
|
||||||
)
|
validate_pld_spec
|
||||||
log.runtime(
|
and
|
||||||
'Reverted to previous pld-spec\n\n'
|
expect_started_mte
|
||||||
f'{orig_pldec}\n'
|
):
|
||||||
|
raise RuntimeError(
|
||||||
|
'Child-ctx-task SHOULD HAVE raised an MTE for\n\n'
|
||||||
|
f'{started_value!r}\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
not expect_started_mte
|
||||||
|
or
|
||||||
|
not validate_pld_spec
|
||||||
|
)
|
||||||
|
|
||||||
|
# if wait_for_parent_to_cancel:
|
||||||
|
# ...
|
||||||
|
#
|
||||||
|
# ^-TODO-^ logic for diff validation policies on each side:
|
||||||
|
#
|
||||||
|
# -[ ] ensure that if we don't validate on the send
|
||||||
|
# side, that we are eventually error-cancelled by our
|
||||||
|
# parent due to the bad `Started` payload!
|
||||||
|
# -[ ] the boxed error should be srced from the parent's
|
||||||
|
# runtime NOT ours!
|
||||||
|
# -[ ] we should still error on bad `return_value`s
|
||||||
|
# despite the parent not yet error-cancelling us?
|
||||||
|
# |_ how do we want the parent side to look in that
|
||||||
|
# case?
|
||||||
|
# -[ ] maybe the equiv of "during handling of the
|
||||||
|
# above error another occurred" for the case where
|
||||||
|
# the parent sends a MTE to this child and while
|
||||||
|
# waiting for the child to terminate it gets back
|
||||||
|
# the MTE for this case?
|
||||||
|
#
|
||||||
|
|
||||||
|
# XXX should always fail on recv side since we can't
|
||||||
|
# really do much else beside terminate and relay the
|
||||||
|
# msg-type-error from this RPC task ;)
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'return_value',
|
'return_value',
|
||||||
|
@ -321,7 +317,6 @@ def test_basic_payload_spec(
|
||||||
child,
|
child,
|
||||||
return_value=return_value,
|
return_value=return_value,
|
||||||
started_value=started_value,
|
started_value=started_value,
|
||||||
pld_spec=maybe_msg_spec,
|
|
||||||
validate_pld_spec=pld_check_started_value,
|
validate_pld_spec=pld_check_started_value,
|
||||||
) as (ctx, first),
|
) as (ctx, first),
|
||||||
):
|
):
|
||||||
|
|
Loading…
Reference in New Issue