mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-06-11 01:14:45 +02:00
63 lines
2.3 KiB
Python
63 lines
2.3 KiB
Python
|
|
"""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
|