Buffer DMRA before VHEAD, wait for hotspot TA in both mode, relay passthrough DMRA once per stream, and dedupe DEBUG policy/embed lines.pull/1/head
parent
67710558e8
commit
84ccbc8f5c
@ -0,0 +1,65 @@
|
||||
"""DMRA may arrive before DMRD VHEAD — legacy buffers under rf_src until stream note."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from adn_server.domain import bytes_3, bytes_4
|
||||
from adn_server.domain.talker_alias import build_dmra_packet, decode_ta_from_blocks
|
||||
from adn_server.infrastructure.hbp_constants import DMRA
|
||||
|
||||
from tests.support.hbp_repeat_stack import build_hbp_repeat_stack
|
||||
from tests.harness.deterministic import DeterministicScenario, PacketSpec
|
||||
from tests.talker_alias.test_mmdvm_wire import mmdvm_wire_blocks
|
||||
|
||||
|
||||
_PEER_TX = bytes_4(730039210)
|
||||
_PEER_RX = bytes_4(730039101)
|
||||
_ADDR_TX = ("10.0.0.1", 62001)
|
||||
_ADDR_RX = ("10.0.0.2", 62002)
|
||||
|
||||
|
||||
def test_dmra_before_vhead_passthrough_on_repeat() -> None:
|
||||
"""Regression: early DMRA was dropped when stream_id mapping did not exist yet."""
|
||||
stack = build_hbp_repeat_stack(talker_alias=True)
|
||||
stack.config["GLOBAL"]["TALKER_ALIAS_MODE"] = "passthrough"
|
||||
stack.register_peer(_PEER_TX, _ADDR_TX)
|
||||
stack.register_peer(_PEER_RX, _ADDR_RX)
|
||||
|
||||
rf_src = bytes_3(3120001)
|
||||
text = "CE5RPY Radio"
|
||||
for block_id, payload in mmdvm_wire_blocks(text).items():
|
||||
stack.inject(build_dmra_packet(rf_src, block_id, payload), _ADDR_TX)
|
||||
|
||||
base = PacketSpec(peer_id=730039210, rf_src=3120001, dst_id=7304, slot=2, stream_id=0xA1B2C3D4)
|
||||
stack.inject_spec(DeterministicScenario.voice_head_spec(base), _ADDR_TX)
|
||||
|
||||
assert stack.dmra_capture, "passthrough DMRA should be sent on VHEAD"
|
||||
packets, exclude = stack.dmra_capture[0]
|
||||
assert exclude == _PEER_TX
|
||||
assert all(p[:4] == DMRA for p in packets)
|
||||
rebuilt = {i: packets[i][8:15] for i in range(len(packets))}
|
||||
assert decode_ta_from_blocks(rebuilt) == text
|
||||
|
||||
dmra_to_rx = [p for p, _ in stack.transport.sent if p[:4] == DMRA and _ == _ADDR_RX]
|
||||
assert dmra_to_rx, "listening peer should receive passthrough DMRA"
|
||||
|
||||
|
||||
def test_promote_provisional_dmra_buffer() -> None:
|
||||
stack = build_hbp_repeat_stack(talker_alias=True)
|
||||
hbp = stack.hbp
|
||||
peer = _PEER_TX
|
||||
rf_src = bytes_3(3120001)
|
||||
stream_id = bytes_4(0x12345678)
|
||||
blocks = mmdvm_wire_blocks("TA early")
|
||||
|
||||
for block_id, payload in blocks.items():
|
||||
hbp.store_dmra_packet(peer, build_dmra_packet(rf_src, block_id, payload))
|
||||
|
||||
assert hbp.get_dmra_blocks(rf_src) is not None
|
||||
assert hbp.get_dmra_blocks(stream_id) is None
|
||||
|
||||
hbp.note_dmrd_stream(peer, rf_src, stream_id)
|
||||
|
||||
promoted = hbp.get_dmra_blocks(stream_id)
|
||||
assert promoted is not None
|
||||
assert decode_ta_from_blocks(promoted) == "TA early"
|
||||
assert hbp.get_dmra_blocks(rf_src) is None
|
||||
@ -0,0 +1,55 @@
|
||||
"""Talker Alias DMRA relay and log deduplication."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from adn_server.application.bridge_use_cases import BridgeUseCases
|
||||
from adn_server.domain import bytes_3, bytes_4
|
||||
from adn_server.infrastructure.bridge_router_impl import InMemoryBridgeRouter
|
||||
from adn_server.infrastructure.talker_alias_emblc import default_ta_emblc_encoder
|
||||
from adn_server.domain.dmr.bptc import encode_emblc
|
||||
|
||||
from tests.harness.scenarios import make_talker_alias_use_cases, talker_alias_config
|
||||
from tests.talker_alias.test_mmdvm_wire import mmdvm_wire_blocks
|
||||
|
||||
|
||||
def test_should_resend_passthrough_only_after_inject() -> None:
|
||||
ta = make_talker_alias_use_cases(talker_alias_config())
|
||||
stream_id = bytes_4(0xA1B2C3D4)
|
||||
|
||||
assert ta.should_resend_passthrough_dmra("SYSTEM", stream_id) is True
|
||||
ta.mark_dmra_sent("SYSTEM", stream_id, kind="inject")
|
||||
assert ta.should_resend_passthrough_dmra("SYSTEM", stream_id) is True
|
||||
ta.mark_dmra_sent("SYSTEM", stream_id, kind="passthrough")
|
||||
assert ta.should_resend_passthrough_dmra("SYSTEM", stream_id) is False
|
||||
|
||||
|
||||
def test_on_dmra_fragment_stored_relays_passthrough_once() -> None:
|
||||
"""Second completion callback must not re-send passthrough DMRA on the same stream."""
|
||||
config = talker_alias_config()
|
||||
config["GLOBAL"]["TALKER_ALIAS_MODE"] = "both"
|
||||
config["SYSTEMS"]["MASTER-A"]["REPEAT"] = True
|
||||
blocks = mmdvm_wire_blocks("CE5RPY")
|
||||
sent: list[str] = []
|
||||
|
||||
def _send_dmra(target_system: str, packets: list[bytes], exclude_peer: bytes | None = None) -> int:
|
||||
sent.append(target_system)
|
||||
return 1
|
||||
|
||||
bridge = BridgeUseCases(
|
||||
InMemoryBridgeRouter(),
|
||||
config,
|
||||
send_dmra_to_system=_send_dmra,
|
||||
get_dmra_blocks=lambda _sys, _sid: blocks,
|
||||
encode_emblc=encode_emblc,
|
||||
ta_emblc_encoder=default_ta_emblc_encoder,
|
||||
)
|
||||
peer = bytes_4(1001)
|
||||
rf_src = bytes_3(3120001)
|
||||
stream_id = bytes_4(0xB1B2B3B4)
|
||||
|
||||
bridge.on_dmra_fragment_stored("MASTER-A", peer, rf_src, stream_id)
|
||||
first_count = len(sent)
|
||||
assert first_count == 1
|
||||
|
||||
bridge.on_dmra_fragment_stored("MASTER-A", peer, rf_src, stream_id)
|
||||
assert len(sent) == first_count
|
||||
Loading…
Reference in new issue