meshai/work/tests/test_config_loader.py

63 lines
2.3 KiB
Python
Raw Normal View History

"""Phase 2.16.1: lock in notification-rule coercion in the config loader path.
Regression guard for the bug where the generic nested-dataclass handler in
_dict_to_dataclass shadowed the explicit 'notifications' branch, leaving
cfg.notifications.rules as raw dicts (which crashed Dispatcher._matching_rules
on rule.enabled). config_loader.load_config uses this same _dict_to_dataclass.
"""
from meshai.config import Config, NotificationRuleConfig, _dict_to_dataclass
def test_multifile_load_coerces_notification_rules():
"""notifications.rules dicts are coerced to NotificationRuleConfig."""
data = {
"notifications": {
"enabled": True,
"rules": [
{
"name": "Test Rule",
"enabled": True,
"trigger_type": "condition",
"categories": ["earthquake_event"],
"min_severity": "routine",
"delivery_type": "mesh_broadcast",
},
{
"name": "Second Rule",
"enabled": False,
"trigger_type": "condition",
"categories": ["wildfire_incident"],
"delivery_type": "email",
},
],
}
}
cfg = _dict_to_dataclass(Config, data)
rules = cfg.notifications.rules
assert len(rules) == 2
# Coerced to the dataclass, NOT left as dicts.
assert all(isinstance(r, NotificationRuleConfig) for r in rules)
# Attribute access (what Dispatcher._matching_rules needs) works.
assert rules[0].enabled is True
assert rules[0].name == "Test Rule"
assert rules[1].enabled is False
def test_rules_attribute_access_does_not_raise():
"""Dispatcher-style attribute access on every rule succeeds."""
data = {
"notifications": {
"rules": [
{"name": "R", "enabled": True, "trigger_type": "condition",
"categories": ["earthquake_event"], "min_severity": "immediate"},
]
}
}
cfg = _dict_to_dataclass(Config, data)
for r in cfg.notifications.rules:
# These are the accesses Dispatcher._matching_rules performs.
_ = r.enabled
_ = r.trigger_type
_ = r.categories
_ = r.min_severity