feat: 完成 issue #33 ② 数据保留/归档/降采样策略配置
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""数据保留/归档/降采样策略配置测试(issue #33)。
|
||||
|
||||
覆盖:
|
||||
1. 模板配置资产加载(保留天数 / 降采样规则 / 归档配置);
|
||||
2. tdengine_keep_days 与 generate_schema 联动(KEEP 参数);
|
||||
3. 降采样 SQL 片段生成 + 点位匹配(protocol / 前缀);
|
||||
4. 归档配置(桶名联动模板命名、对象保留期);
|
||||
5. 非法配置拒绝(keep_days≤0 / 非法 agg / 归档保留期≤0)。
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import _bootstrap # noqa: F401
|
||||
|
||||
from data_bus.retention_policy import ( # noqa: E402
|
||||
ALLOWED_AGGS,
|
||||
DEFAULT_CONFIG_PATH,
|
||||
DownsampleRule,
|
||||
RetentionPolicy,
|
||||
)
|
||||
from data_bus.tdengine_schema import ( # noqa: E402
|
||||
generate_schema,
|
||||
specs_from_point_dict_rows,
|
||||
)
|
||||
from data_bus.templating import TemplateNaming # noqa: E402
|
||||
|
||||
CONFIG = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"config", "retention.template.yaml",
|
||||
)
|
||||
|
||||
|
||||
class TestConfigLoad(unittest.TestCase):
|
||||
"""配置资产加载。"""
|
||||
|
||||
def setUp(self):
|
||||
self.policy = RetentionPolicy.from_template_config(CONFIG)
|
||||
|
||||
def test_template_and_keep(self):
|
||||
self.assertEqual(self.policy.template, "ti-cl4")
|
||||
self.assertEqual(self.policy.tdengine_keep_days(), 90)
|
||||
|
||||
def test_downsampling_rules(self):
|
||||
rules = self.policy.downsampling_rules()
|
||||
self.assertEqual(len(rules), 2)
|
||||
self.assertEqual(rules[0].interval, "1m")
|
||||
self.assertEqual(rules[0].agg, "avg")
|
||||
self.assertEqual(rules[0].keep_days, 730)
|
||||
|
||||
def test_archive_config(self):
|
||||
cfg = self.policy.archive_config()
|
||||
self.assertTrue(cfg["enabled"])
|
||||
self.assertEqual(cfg["bucket"], "ti-cl4-archive")
|
||||
self.assertEqual(cfg["retention_days"], 3650)
|
||||
|
||||
def test_default_config_path_exists(self):
|
||||
self.assertTrue(os.path.isfile(DEFAULT_CONFIG_PATH))
|
||||
|
||||
|
||||
class TestKeepLinkedToSchema(unittest.TestCase):
|
||||
"""保留天数与 TDengine schema 联动(KEEP)。"""
|
||||
|
||||
def test_generate_schema_uses_keep_days(self):
|
||||
policy = RetentionPolicy.from_template_config(CONFIG)
|
||||
naming = TemplateNaming("ti-cl4")
|
||||
rows = [{"device_id": "CLF-01", "point_id": "CLF-01.TEMP",
|
||||
"unit": "℃", "dataType": "float"}]
|
||||
ddl = generate_schema(
|
||||
naming, specs_from_point_dict_rows(rows),
|
||||
retention_days=policy.tdengine_keep_days())[0]
|
||||
self.assertIn(f"KEEP({policy.tdengine_keep_days()})", ddl)
|
||||
|
||||
|
||||
class TestDownsampleSql(unittest.TestCase):
|
||||
"""降采样 SQL 生成与点位匹配。"""
|
||||
|
||||
def setUp(self):
|
||||
self.policy = RetentionPolicy.from_template_config(CONFIG)
|
||||
|
||||
def test_sql_fragment(self):
|
||||
rule = DownsampleRule(name="r", interval="1m", agg="avg", keep_days=730)
|
||||
sql = rule.sql_fragment("tpl_ti_cl4.CLF_01_TEMP")
|
||||
self.assertIn("SELECT _wstart AS ts", sql)
|
||||
self.assertIn("avg(value) AS value_agg", sql)
|
||||
self.assertIn("INTERVAL(1m)", sql)
|
||||
|
||||
def test_matching_rules_by_protocol(self):
|
||||
hits = self.policy.matching_rules(
|
||||
{"point_id": "CLF-01.TEMP", "protocol": "opcua"})
|
||||
self.assertEqual([h.name for h in hits], ["raw_1m_avg"])
|
||||
|
||||
def test_matching_rules_by_prefix(self):
|
||||
# 无匹配规则时返回空(energy 规则不命中 opcua 点位)
|
||||
hits = self.policy.matching_rules(
|
||||
{"point_id": "CLF-01.TEMP", "protocol": "opcua"})
|
||||
self.assertNotIn("energy_1h_sum", [h.name for h in hits])
|
||||
|
||||
def test_allowed_aggs(self):
|
||||
self.assertTrue({"avg", "max", "min", "last", "sum"} <= ALLOWED_AGGS)
|
||||
|
||||
|
||||
class TestValidation(unittest.TestCase):
|
||||
"""非法配置拒绝。"""
|
||||
|
||||
def test_keep_days_positive(self):
|
||||
with self.assertRaises(ValueError):
|
||||
RetentionPolicy(template="t", raw_keep_days=0)
|
||||
|
||||
def test_invalid_agg(self):
|
||||
with self.assertRaises(ValueError):
|
||||
RetentionPolicy(
|
||||
template="t",
|
||||
downsampling=[{"name": "r", "interval": "1m",
|
||||
"agg": "median", "keep_days": 30}])
|
||||
|
||||
def test_archive_retention_positive(self):
|
||||
with self.assertRaises(ValueError):
|
||||
RetentionPolicy(
|
||||
template="t",
|
||||
archive={"enabled": True, "retention_days": 0})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user