Compare commits
1
Commits
b472f91f19
...
v1.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8180082f90 |
@@ -98,8 +98,10 @@ def _validate_field_value(kind: str, field: SourceConfigField, value: Any) -> No
|
||||
_check_type(field, value)
|
||||
if field.name == "path" and not value.startswith("/dev/"):
|
||||
raise SourceProfileError("warmtelink_serial config path must start with '/dev/'.")
|
||||
if field.name in {"broker_port", "sample_interval_s", "baudrate"} and value <= 0:
|
||||
if field.name in {"broker_port", "baudrate"} and value <= 0:
|
||||
raise SourceProfileError(f"Config field {field.name!r} must be greater than zero.")
|
||||
if field.name == "sample_interval_s" and value < 0:
|
||||
raise SourceProfileError("Config field 'sample_interval_s' must not be negative.")
|
||||
if field.name == "data_bits" and value != 7:
|
||||
raise SourceProfileError("warmtelink_serial data_bits must be 7.")
|
||||
if field.name == "parity" and value != "N":
|
||||
|
||||
@@ -12,6 +12,8 @@ from alembic import command
|
||||
from alembic.config import Config
|
||||
from sqlalchemy import create_engine, event, inspect, text
|
||||
|
||||
from app.integrations.meter_sources import sanitize_source_config, validate_source_config
|
||||
|
||||
|
||||
def _config(database_url: str) -> Config:
|
||||
config = Config("alembic_app.ini")
|
||||
@@ -108,7 +110,7 @@ def test_populated_revision_14_adopts_dsmr_history_at_revision_16(tmp_path: Path
|
||||
{"key": "DSMR_INGEST_ENABLED", "value": "true", "at": start},
|
||||
{"key": "DSMR_MQTT_TOPIC", "value": "historic/dsmr", "at": start},
|
||||
{"key": "DSMR_TARIFF_TOPIC", "value": "historic/tariff", "at": start},
|
||||
{"key": "DSMR_SAMPLE_INTERVAL_S", "value": "15", "at": start},
|
||||
{"key": "DSMR_SAMPLE_INTERVAL_S", "value": "0", "at": start},
|
||||
{"key": "MQTT_BROKER_HOST", "value": "mqtt.example.invalid", "at": start},
|
||||
{"key": "MQTT_BROKER_PORT", "value": "1884", "at": start},
|
||||
{"key": "MQTT_USERNAME", "value": "historic-user", "at": start},
|
||||
@@ -159,11 +161,14 @@ def test_populated_revision_14_adopts_dsmr_history_at_revision_16(tmp_path: Path
|
||||
text("SELECT id, enabled, config FROM meter_source WHERE kind = 'dsmr_mqtt'")
|
||||
).one()
|
||||
assert source.enabled == 1
|
||||
assert json.loads(source.config) == {
|
||||
source_config = json.loads(source.config)
|
||||
assert source_config == {
|
||||
"broker_host": "mqtt.example.invalid", "broker_port": 1884,
|
||||
"username": "historic-user", "password": "historic-password", "tls_enabled": True,
|
||||
"topic": "historic/dsmr", "tariff_topic": "historic/tariff", "sample_interval_s": 15,
|
||||
"topic": "historic/dsmr", "tariff_topic": "historic/tariff", "sample_interval_s": 0,
|
||||
}
|
||||
assert validate_source_config("dsmr_mqtt", source_config) == source_config
|
||||
assert sanitize_source_config("dsmr_mqtt", source_config)["sample_interval_s"] == 0
|
||||
assert connection.execute(text("SELECT value FROM app_config WHERE key = 'DSMR_MQTT_TOPIC'")).scalar_one() == "historic/dsmr"
|
||||
assert dict(connection.execute(text("SELECT key, value FROM app_config")).all()) == config_before
|
||||
assert connection.execute(text("SELECT group_concat(telegram_id) FROM dsmr_reading")).scalar_one() == "77,78,77"
|
||||
|
||||
@@ -68,6 +68,32 @@ def test_secret_sanitize_and_mask_merge_keep_old_value():
|
||||
assert merged["topic"] == "new/topic"
|
||||
|
||||
|
||||
def test_dsmr_zero_interval_validates_sanitizes_and_merges_unchanged():
|
||||
config = validate_source_config("dsmr_mqtt", {"sample_interval_s": 0})
|
||||
|
||||
assert config["sample_interval_s"] == 0
|
||||
assert sanitize_source_config("dsmr_mqtt", config)["sample_interval_s"] == 0
|
||||
assert merge_source_config("dsmr_mqtt", config, {"topic": "new/topic"})["sample_interval_s"] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("kind", "config"),
|
||||
[
|
||||
("dsmr_mqtt", {"sample_interval_s": -1}),
|
||||
("dsmr_mqtt", {"sample_interval_s": False}),
|
||||
("dsmr_mqtt", {"broker_port": 0}),
|
||||
("dsmr_mqtt", {"broker_port": -1}),
|
||||
("dsmr_mqtt", {"broker_port": False}),
|
||||
("warmtelink_serial", {"path": "/dev/warmtelink", "baudrate": 0}),
|
||||
("warmtelink_serial", {"path": "/dev/warmtelink", "baudrate": -1}),
|
||||
("warmtelink_serial", {"path": "/dev/warmtelink", "baudrate": False}),
|
||||
],
|
||||
)
|
||||
def test_numeric_source_profile_constraints_still_reject_invalid_values(kind, config):
|
||||
with pytest.raises(SourceProfileError):
|
||||
validate_source_config(kind, config)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def session(tmp_path):
|
||||
engine = create_engine(f"sqlite:///{tmp_path / 'source_services.db'}")
|
||||
|
||||
Reference in New Issue
Block a user