Files
meshcore-bot/tests/characterization/test_bot_identity_matrix.py
T
agessaman f829ed9ddd test(characterization): pin packaging coverage and the web viewer route table
The packaging test checks pyproject.toml against git ls-files: every directory under modules/ with Python files must be a regular package, and every tracked runtime data file must match a package-data glob, since include-package-data is off and a new subpackage or data file would otherwise silently miss the wheel. The endpoint inventory records all 104 routes with their methods and endpoint names, plus the status, content type, redirect target, script-src CSP (nonce normalized) and framing headers of anonymous requests with and without a password, and of anonymous mutating requests when locked. Endpoint names feed the CSP nonce allowlist and url_for, so a helper extraction that renames or reroutes anything shows up here.
2026-10-01 01:02:33 -07:00

87 lines
3.1 KiB
Python

"""Characterization: every node-name lookup against every ``self_info`` shape.
The bot reads its own name in several places with different fallback orders and
different presence/truthiness rules (budget paths read ``name``/``user_name``,
mention matching reads ``name``/``adv_name``, and BaseCommand's object branch
tests attribute presence rather than truthiness). Consolidating them must keep
each caller's current answer; this golden file records it.
"""
from __future__ import annotations
import configparser
import itertools
from types import SimpleNamespace
from unittest.mock import MagicMock, Mock
from modules.command_manager import CommandManager
from modules.commands.base_command import BaseCommand
from modules.models import MeshMessage
from modules.scheduler import MessageScheduler
from tests.characterization.golden_util import assert_golden
FIELDS = ("name", "user_name", "adv_name")
VALUES = (None, "", "Dev") # None = field absent
class _Cmd(BaseCommand):
name = "probe"
keywords = ["probe"]
async def execute(self, message): # pragma: no cover - abstract stub
return True
def _shapes():
yield "self_info=None", None
for combo in itertools.product(VALUES, repeat=len(FIELDS)):
present = {f: (f"{v}-{f}" if v == "Dev" else v) for f, v in zip(FIELDS, combo, strict=True) if v is not None}
label = ",".join(f"{k}={v!r}" for k, v in present.items()) or "empty"
yield f"dict[{label}]", dict(present)
yield f"obj[{label}]", SimpleNamespace(**present)
def _bot(self_info, config_name):
cfg = configparser.ConfigParser()
cfg.add_section("Bot")
if config_name is not None:
cfg.set("Bot", "bot_name", config_name)
cfg.add_section("Channels")
bot = MagicMock()
bot.config = cfg
bot.logger = Mock()
bot.meshcore = MagicMock()
bot.meshcore.self_info = self_info
return bot
def _safe(fn):
try:
return fn()
except Exception as exc: # noqa: BLE001 - the exception type is the behavior
return f"<raises {type(exc).__name__}>"
def test_node_name_lookups():
results = {}
for (label, self_info), config_name in itertools.product(list(_shapes()), [None, "", "CfgBot"]):
bot = _bot(self_info, config_name)
cm = object.__new__(CommandManager)
cm.bot = bot
cm.logger = bot.logger
cmd = object.__new__(_Cmd)
cmd.bot = bot
cmd.logger = bot.logger
sched = object.__new__(MessageScheduler)
sched.bot = bot
sched.logger = bot.logger
channel_msg = MeshMessage(content="x", channel="general", is_dm=False)
results[f"{label} config_bot_name={config_name!r}"] = {
"cm.get_max_message_length": _safe(lambda: cm.get_max_message_length(channel_msg)),
"cm.channel_body_budget": _safe(lambda: cm.channel_body_budget(channel="general")),
"cmd.get_max_message_length": _safe(lambda: cmd.get_max_message_length(channel_msg)),
"cmd._get_bot_name": _safe(cmd._get_bot_name),
"scheduler._channel_body_budget": _safe(lambda: sched._channel_body_budget(None)),
}
assert_golden("bot_identity_matrix", results)