feat: add detection + forecast modules with tests
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"""detection 模块测试(mock TDengine execute 返回预设窗口)。"""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
import pytest
|
||||
from ts_anomaly_td.detection import run_anomaly_window, detect_all_algos, ALL_ALGOS
|
||||
|
||||
|
||||
def make_mock_conn(rows=None):
|
||||
"""构造 mock TDConnection,execute 返回预设行。"""
|
||||
conn = MagicMock()
|
||||
conn.execute.return_value = rows or []
|
||||
return conn
|
||||
|
||||
|
||||
def test_run_anomaly_window_returns_windows():
|
||||
"""正常返回两个异常窗口。"""
|
||||
conn = make_mock_conn([
|
||||
(1000000, 2000000),
|
||||
(3000000, 4000000),
|
||||
])
|
||||
windows = run_anomaly_window(conn, "finance_001", "ksigma")
|
||||
assert windows == [(1000000, 2000000), (3000000, 4000000)]
|
||||
|
||||
|
||||
def test_run_anomaly_window_empty():
|
||||
"""无异常窗口时返回空列表。"""
|
||||
conn = make_mock_conn([])
|
||||
windows = run_anomaly_window(conn, "finance_001", "iqr")
|
||||
assert windows == []
|
||||
|
||||
|
||||
def test_run_anomaly_window_invalid_algo():
|
||||
"""不支持的算法抛 ValueError。"""
|
||||
conn = make_mock_conn()
|
||||
with pytest.raises(ValueError, match="不支持的算法"):
|
||||
run_anomaly_window(conn, "test", "nonexistent")
|
||||
|
||||
|
||||
def test_run_anomaly_window_sql_error():
|
||||
"""SQL 执行失败传播异常。"""
|
||||
conn = make_mock_conn()
|
||||
conn.execute.side_effect = Exception("TDengine error")
|
||||
|
||||
with pytest.raises(Exception, match="TDengine error"):
|
||||
run_anomaly_window(conn, "test", "ksigma")
|
||||
|
||||
|
||||
def test_detect_all_algos_independent_fault_tolerance():
|
||||
"""单个算法失败不影响其他算法。"""
|
||||
conn = MagicMock()
|
||||
|
||||
def side_effect(sql):
|
||||
if "iqr" in sql:
|
||||
raise Exception("iqr failed")
|
||||
return [(1000, 2000)]
|
||||
|
||||
conn.execute.side_effect = side_effect
|
||||
|
||||
results = detect_all_algos(conn, "test")
|
||||
|
||||
# 所有 6 个算法都在结果中
|
||||
assert set(results.keys()) == set(ALL_ALGOS)
|
||||
|
||||
# iqr 记录了 error
|
||||
assert results["iqr"]["error"] == "iqr failed"
|
||||
assert results["iqr"]["windows"] == []
|
||||
|
||||
# 其他算法正常
|
||||
for algo in ALL_ALGOS:
|
||||
if algo != "iqr":
|
||||
assert results[algo]["error"] is None
|
||||
assert len(results[algo]["windows"]) == 1
|
||||
|
||||
|
||||
def test_detect_all_algos_custom_algo_list():
|
||||
"""指定算法子集。"""
|
||||
conn = make_mock_conn([(1000, 2000)])
|
||||
results = detect_all_algos(conn, "test", algos=["ksigma", "iqr"])
|
||||
assert set(results.keys()) == {"ksigma", "iqr"}
|
||||
Reference in New Issue
Block a user