A direct message was transmitted once and marked failed the moment its single delivery-ack window lapsed, leaving Ctrl-R as the only recourse. Now the send path re-sends an unacknowledged message automatically before giving up, matching the mesh convention of a few tries. _deliver_direct loops send_direct_message until an ack lands or the budget is spent; both the initial send and the manual Ctrl-R resend route through it. Each attempt already blocks a full ack window before the next, so the retries are spaced by that window rather than hammering the radio, and a hard send rejection propagates without retry. The budget is the new direct_message_soft_retries setting: retries + 1 tries, clamped to 0..2 so a message is never re-broadcast more than twice (0 = one shot, default 2 = up to three tries). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
1.8 KiB
Python
44 lines
1.8 KiB
Python
"""Tests for application settings loading."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from meshterm.core.config import DIRECT_MESSAGE_MAX_SOFT_RETRIES, Settings
|
|
|
|
|
|
def test_connect_on_start_defaults_true() -> None:
|
|
"""Eager connect-at-launch is the default when nothing is configured."""
|
|
assert Settings().connect_on_start is True
|
|
|
|
|
|
def test_connect_on_start_loads_from_toml(tmp_path: Path) -> None:
|
|
"""The connect_on_start preference round-trips from the config file."""
|
|
config = tmp_path / "config.toml"
|
|
config.write_text("connect_on_start = false\n", encoding="utf-8")
|
|
assert Settings.load(config).connect_on_start is False
|
|
|
|
|
|
def test_direct_message_soft_retries_defaults_to_two() -> None:
|
|
"""Two soft retries (three tries total) is the out-of-the-box direct-message budget."""
|
|
assert Settings().direct_message_soft_retries == 2
|
|
assert DIRECT_MESSAGE_MAX_SOFT_RETRIES == 2
|
|
|
|
|
|
def test_direct_message_soft_retries_loads_from_toml(tmp_path: Path) -> None:
|
|
"""The soft-retry budget round-trips from the config file."""
|
|
config = tmp_path / "config.toml"
|
|
config.write_text("direct_message_soft_retries = 1\n", encoding="utf-8")
|
|
assert Settings.load(config).direct_message_soft_retries == 1
|
|
|
|
|
|
def test_direct_message_soft_retries_clamped_to_range(tmp_path: Path) -> None:
|
|
"""Out-of-range values are clamped to 0..2 so a DM never floods the mesh (or is dropped)."""
|
|
hot = tmp_path / "hot.toml"
|
|
hot.write_text("direct_message_soft_retries = 9\n", encoding="utf-8")
|
|
assert Settings.load(hot).direct_message_soft_retries == DIRECT_MESSAGE_MAX_SOFT_RETRIES
|
|
|
|
cold = tmp_path / "cold.toml"
|
|
cold.write_text("direct_message_soft_retries = -4\n", encoding="utf-8")
|
|
assert Settings.load(cold).direct_message_soft_retries == 0
|